blob: 0aa2294dba64055b5af3c9973a7381563b0e0e11 [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
adminbae64d82013-08-01 10:50:15 -070039import openspeak
Hari Krishnabe4b97b2015-07-15 12:19:43 -070040import subprocess
Jon Hall4dbbbd62021-10-18 15:33:42 -070041module = new.module( "test" )
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 -070054from core.utilities import Utilities
kelvin-onlabfb521662015-02-27 09:52:40 -080055from core.Thread import Thread
adminbae64d82013-08-01 10:50:15 -070056
Jon Hall4dbbbd62021-10-18 15:33:42 -070057
Jon Hallca319892017-06-15 15:25:22 -070058class SkipCase( Exception ):
59 pass
60
Jon Hall4dbbbd62021-10-18 15:33:42 -070061
adminbae64d82013-08-01 10:50:15 -070062class TestON:
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +000063 '''
kelvin-onlabf70fd542015-05-07 18:41:40 -070064 TestON will initiate the specified test.
Jon Hall714eeba2015-09-29 17:53:10 -070065 The main tasks are:
kelvin-onlabf70fd542015-05-07 18:41:40 -070066 * Initiate the required Component handles for the test.
adminbae64d82013-08-01 10:50:15 -070067 * Create Log file Handles.
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +000068 '''
Jon Hall714eeba2015-09-29 17:53:10 -070069 def __init__( self, options ):
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +000070 '''
Jon Hall714eeba2015-09-29 17:53:10 -070071 Initialise the component handles specified in the topology file of
72 the specified test.
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +000073 '''
adminbae64d82013-08-01 10:50:15 -070074 # Initialization of the variables.
75 __builtin__.main = self
adminbae64d82013-08-01 10:50:15 -070076 __builtin__.path = path
77 __builtin__.utilities = Utilities()
Jon Hall4c3d44b2021-10-07 11:23:27 -070078 __builtin__.SkipCase = SkipCase
adminbae64d82013-08-01 10:50:15 -070079 self.TRUE = 1
80 self.FALSE = 0
81 self.ERROR = -1
kelvin-onlabf70fd542015-05-07 18:41:40 -070082 self.NORESULT = 2
adminbae64d82013-08-01 10:50:15 -070083 self.FAIL = False
84 self.PASS = True
kelvin-onlabf70fd542015-05-07 18:41:40 -070085 self.CASERESULT = self.ERROR
86 self.STEPRESULT = self.NORESULT
adminbae64d82013-08-01 10:50:15 -070087 self.init_result = self.TRUE
88 self.testResult = "Summary"
kelvin-onlabf70fd542015-05-07 18:41:40 -070089 self.stepName = ""
90 self.stepCache = ""
Jon Halld61331b2015-02-17 16:35:47 -080091 self.EXPERIMENTAL_MODE = False
adminbae64d82013-08-01 10:50:15 -070092 self.test_target = None
93 self.lastcommand = None
Jon Halld61331b2015-02-17 16:35:47 -080094 self.testDir = tests_path
Jon Halld74d2952018-03-01 13:26:39 -080095 self.testsRoot = tests_path
Jon Halld61331b2015-02-17 16:35:47 -080096 self.configFile = config_path + "teston.cfg"
adminbae64d82013-08-01 10:50:15 -070097 self.parsingClass = "xmlparser"
98 self.parserPath = core_path + "/xmlparser"
99 self.loggerPath = core_path + "/logger"
100 self.loggerClass = "Logger"
101 self.logs_path = logs_path
102 self.driver = ''
kelvin-onlabfb521662015-02-27 09:52:40 -0800103 self.Thread = Thread
Jon Hall5b586732015-06-11 11:39:39 -0700104 self.cleanupFlag = False
105 self.cleanupLock = threading.Lock()
Jon Hall0fc0d452015-07-14 09:49:58 -0700106 self.initiated = False
Devin Limec989792017-08-15 15:57:55 -0700107 self.executedCase = []
108 self.leftCase = []
109 self.failedCase = []
110 self.noResultCase = []
Jon Hall65844a32015-03-09 19:09:37 -0700111
Jon Hall25079782015-10-13 13:54:39 -0700112 self.config = self.configparser()
Jon Hall714eeba2015-09-29 17:53:10 -0700113 verifyOptions( options )
adminbae64d82013-08-01 10:50:15 -0700114 load_logger()
115 self.componentDictionary = {}
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700116 self.componentDictionary = self.topology[ 'COMPONENT' ]
Jon Hall714eeba2015-09-29 17:53:10 -0700117 self.driversList = []
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700118 if isinstance( self.componentDictionary, str ):
Jon Hall714eeba2015-09-29 17:53:10 -0700119 self.componentDictionary = dict( self.componentDictionary )
Jon Hall65844a32015-03-09 19:09:37 -0700120
Jon Hall714eeba2015-09-29 17:53:10 -0700121 for component in self.componentDictionary:
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700122 self.driversList.append( self.componentDictionary[ component ][ 'type' ] )
Jon Hall65844a32015-03-09 19:09:37 -0700123
Jon Hall714eeba2015-09-29 17:53:10 -0700124 self.driversList = list( set( self.driversList ) ) # Removing duplicates.
adminbae64d82013-08-01 10:50:15 -0700125 # Checking the test_target option set for the component or not
Jon Hall714eeba2015-09-29 17:53:10 -0700126 if isinstance( self.componentDictionary, dict ):
adminbae64d82013-08-01 10:50:15 -0700127 for component in self.componentDictionary.keys():
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700128 if 'test_target' in self.componentDictionary[ component ].keys():
adminbae64d82013-08-01 10:50:15 -0700129 self.test_target = component
Jon Hall65844a32015-03-09 19:09:37 -0700130
Jon Halld61331b2015-02-17 16:35:47 -0800131 # Checking for the openspeak file and test script
Jon Hall714eeba2015-09-29 17:53:10 -0700132 self.logger.initlog( self )
adminbae64d82013-08-01 10:50:15 -0700133
134 # Creating Drivers Handles
Jon Hall714eeba2015-09-29 17:53:10 -0700135 initString = "\n" + "*" * 30 + "\n CASE INIT \n" + "*" * 30 + "\n"
136 self.log.exact( initString )
adminbae64d82013-08-01 10:50:15 -0700137 self.driverObject = {}
Jon Hall714eeba2015-09-29 17:53:10 -0700138 self.random_order = 111 # Random order id to connect the components
adminbae64d82013-08-01 10:50:15 -0700139 components_connect_order = {}
Jon Hall714eeba2015-09-29 17:53:10 -0700140 if isinstance( self.componentDictionary, dict ):
adminbae64d82013-08-01 10:50:15 -0700141 for component in self.componentDictionary.keys():
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700142 if 'connect_order' not in self.componentDictionary[ component ].keys():
143 self.componentDictionary[ component ][ 'connect_order' ] = str( self.get_random() )
144 components_connect_order[ component ] = eval( self.componentDictionary[ component ][ 'connect_order' ] )
Jon Hall714eeba2015-09-29 17:53:10 -0700145 # Ordering components based on the connect order.
146 ordered_component_list = sorted( components_connect_order,
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700147 key=lambda key: components_connect_order[ key ] )
adminbae64d82013-08-01 10:50:15 -0700148 print ordered_component_list
adminbae64d82013-08-01 10:50:15 -0700149 for component in ordered_component_list:
Jon Hall714eeba2015-09-29 17:53:10 -0700150 self.componentInit( component )
adminbae64d82013-08-01 10:50:15 -0700151
Jon Hall714eeba2015-09-29 17:53:10 -0700152 def configparser( self ):
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000153 '''
154 It will parse the config file (teston.cfg) and return as dictionary
155 '''
Jon Hall714eeba2015-09-29 17:53:10 -0700156 matchFileName = re.match( r'(.*)\.cfg', self.configFile, re.M | re.I )
adminbae64d82013-08-01 10:50:15 -0700157 if matchFileName:
Jon Hall714eeba2015-09-29 17:53:10 -0700158 xml = open( self.configFile ).read()
159 try:
160 self.configDict = xmldict.xml_to_dict( xml )
adminbae64d82013-08-01 10:50:15 -0700161 return self.configDict
Jon Hall1306a562015-09-04 11:21:24 -0700162 except IOError:
adminbae64d82013-08-01 10:50:15 -0700163 print "There is no such file to parse " + self.configFile
Jon Hall1306a562015-09-04 11:21:24 -0700164 else:
165 print "There is no such file to parse " + self.configFile
kelvin-onlabf70fd542015-05-07 18:41:40 -0700166
Jon Hall714eeba2015-09-29 17:53:10 -0700167 def componentInit( self, component ):
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000168 '''
adminbae64d82013-08-01 10:50:15 -0700169 This method will initialize specified component
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000170 '''
adminbae64d82013-08-01 10:50:15 -0700171 global driver_options
Jon Hall0fc0d452015-07-14 09:49:58 -0700172 self.initiated = False
Jon Hall3a03cad2021-04-07 11:21:55 -0700173 self.log.info( "Creating component handle: " + component )
Jon Halld61331b2015-02-17 16:35:47 -0800174 driver_options = {}
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700175 if 'COMPONENTS' in self.componentDictionary[ component ].keys():
176 driver_options = dict( self.componentDictionary[ component ][ 'COMPONENTS' ] )
177 driver_options[ 'name' ] = component
178 driverName = self.componentDictionary[ component ][ 'type' ]
179 driver_options[ 'type' ] = driverName
Jon Hall06fd0df2021-01-25 15:50:06 -0800180 driver_home = self.componentDictionary[ component ].get( 'home' )
181 if driver_home:
182 driver_options[ 'home' ] = driver_home
kelvin-onlabf70fd542015-05-07 18:41:40 -0700183
Jon Hall714eeba2015-09-29 17:53:10 -0700184 classPath = self.getDriverPath( driverName.lower() )
185 driverModule = importlib.import_module( classPath )
186 driverClass = getattr( driverModule, driverName )
adminbae64d82013-08-01 10:50:15 -0700187 driverObject = driverClass()
kelvin-onlabf70fd542015-05-07 18:41:40 -0700188
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700189 if "OCN" in self.componentDictionary[ component ][ 'host' ] and\
Jon Hall714eeba2015-09-29 17:53:10 -0700190 main.onoscell:
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700191 self.componentDictionary[ component ][ 'host' ] = main.mnIP
Hari Krishnabe4b97b2015-07-15 12:19:43 -0700192
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700193 user_name = self.componentDictionary[ component ].get( 'user', getpass.getuser() )
194 ip_address = self.componentDictionary[ component ].get( 'host', 'localhost' )
195 pwd = self.componentDictionary[ component ].get( 'password', 'changeme' )
196 port = self.componentDictionary[ component ].get( 'port' )
Jon Hall714eeba2015-09-29 17:53:10 -0700197 connect_result = driverObject.connect( user_name=user_name,
198 ip_address=ip_address,
199 pwd=pwd,
200 port=port,
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700201 options=driver_options )
cameron@onlab.us5cc6a372015-05-11 17:18:07 -0700202
adminbae64d82013-08-01 10:50:15 -0700203 if not connect_result:
Jon Hall714eeba2015-09-29 17:53:10 -0700204 self.log.error( "Exiting from the test execution because connecting to the " +
205 component + " component failed." )
Jon Halld61331b2015-02-17 16:35:47 -0800206 self.exit()
kelvin-onlabf70fd542015-05-07 18:41:40 -0700207
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700208 vars( self )[ component ] = driverObject
Jon Hall0fc0d452015-07-14 09:49:58 -0700209 self.initiated = True
Jon Hallca319892017-06-15 15:25:22 -0700210 return driverObject
kelvin-onlabf70fd542015-05-07 18:41:40 -0700211
Jon Hall714eeba2015-09-29 17:53:10 -0700212 def run( self ):
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000213 '''
Jon Hall714eeba2015-09-29 17:53:10 -0700214 The Execution of the test script's cases listed in the Test params
215 file will be done here then update each test case result.
216 This method will return main.TRUE if it executed all the test cases
217 successfully, else will retun main.FALSE
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000218 '''
adminbae64d82013-08-01 10:50:15 -0700219 self.testCaseResult = {}
Jon Halla1185982014-09-15 14:55:10 -0700220 self.TOTAL_TC = 0
adminbae64d82013-08-01 10:50:15 -0700221 self.TOTAL_TC_RUN = 0
Jon Halld61331b2015-02-17 16:35:47 -0800222 self.TOTAL_TC_PLANNED = 0
adminbae64d82013-08-01 10:50:15 -0700223 self.TOTAL_TC_NORESULT = 0
224 self.TOTAL_TC_FAIL = 0
225 self.TOTAL_TC_PASS = 0
Jon Halla1185982014-09-15 14:55:10 -0700226 self.TEST_ITERATION = 0
Jon Hall714eeba2015-09-29 17:53:10 -0700227
228 # NOTE: number of main.step statements in the
229 # outer most level of the test case. used to
230 # execute code in smaller steps
231 self.stepCount = 0
kelvin-onlabf70fd542015-05-07 18:41:40 -0700232 self.CASERESULT = self.NORESULT
233
Jon Halld61331b2015-02-17 16:35:47 -0800234 import testparser
Jon Hall53c5e662016-04-13 16:06:56 -0700235 test = testparser.TestParser( main.testFile )
adminbae64d82013-08-01 10:50:15 -0700236 self.testscript = test.testscript
237 self.code = test.getStepCode()
Jon Hall714eeba2015-09-29 17:53:10 -0700238 repeat = int( self.params.get( 'repeat', 1 ) )
239 self.TOTAL_TC_PLANNED = len( self.testcases_list ) * repeat
Jon Hall026bd712021-08-31 16:30:09 -0700240 self.log.TAP( "1..%s" % self.TOTAL_TC_PLANNED )
kelvin-onlabf70fd542015-05-07 18:41:40 -0700241
Jon Hall4dbbbd62021-10-18 15:33:42 -0700242 executed = self.TRUE
Jon Hall714eeba2015-09-29 17:53:10 -0700243 while repeat:
Devin Limec989792017-08-15 15:57:55 -0700244 self.leftCase.extend( self.testcases_list )
Jon Halla1185982014-09-15 14:55:10 -0700245 for self.CurrentTestCaseNumber in self.testcases_list:
Devin Limec989792017-08-15 15:57:55 -0700246 self.executedCase.append( self.leftCase.pop( 0 ) )
Jon Hall4dbbbd62021-10-18 15:33:42 -0700247 executed = self.runCase( self.CurrentTestCaseNumber )
Jon Hall714eeba2015-09-29 17:53:10 -0700248 repeat -= 1
Jon Hall4dbbbd62021-10-18 15:33:42 -0700249 return executed
kelvin-onlabf70fd542015-05-07 18:41:40 -0700250
Jon Halle234cc42015-08-31 15:26:47 -0700251 def runCase( self, testCaseNumber ):
adminbae64d82013-08-01 10:50:15 -0700252 self.CurrentTestCaseNumber = testCaseNumber
kelvin-onlabf70fd542015-05-07 18:41:40 -0700253 self.CurrentTestCase = ""
Jon Hall714eeba2015-09-29 17:53:10 -0700254
255 # List of step results in a case. ANDed together to get the result
256 self.stepResultsList = []
kelvin-onlabf70fd542015-05-07 18:41:40 -0700257 self.stepName = ""
Jon Hall783bbf92015-07-23 14:33:19 -0700258 self.caseExplanation = ""
Jon Halla8cf76a2021-10-05 14:31:47 -0700259 self.CASERESULT = self.ERROR
260 self.STEPRESULT = self.NORESULT
Jon Hall4dbbbd62021-10-18 15:33:42 -0700261 executed = self.TRUE
Jon Hall714eeba2015-09-29 17:53:10 -0700262
263 # NOTE: number of main.step statements in the
264 # outer most level of the test case. used to
265 # execute code in smaller steps
266 self.stepCount = 0
267
268 # NOTE: This is the current number of main.step()'s executed
269 # in a case. Used for logging.
270 self.stepNumber = 0
adminbae64d82013-08-01 10:50:15 -0700271 self.EXPERIMENTAL_MODE = self.FALSE
272 self.addCaseHeader()
Devin Limec989792017-08-15 15:57:55 -0700273 self.log.debug( "Case Executed : " + str( self.executedCase ) )
274 self.log.debug( "Case to be executed : " + str( self.leftCase ) )
Jon Halle234cc42015-08-31 15:26:47 -0700275 self.testCaseNumber = str( testCaseNumber )
276 self.CASERESULT = self.NORESULT
adminbae64d82013-08-01 10:50:15 -0700277 stopped = False
Jon Hall5a72b712015-09-28 12:20:59 -0700278 try:
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700279 self.code[ self.testCaseNumber ]
Jon Halld61331b2015-02-17 16:35:47 -0800280 except KeyError:
Jon Halle234cc42015-08-31 15:26:47 -0700281 self.log.error( "There is no Test-Case " + self.testCaseNumber )
Jon Hallfebb1c72015-03-05 13:30:09 -0800282 return self.FALSE
adminbae64d82013-08-01 10:50:15 -0700283 self.stepCount = 0
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700284 while self.stepCount < len( self.code[ self.testCaseNumber ].keys() ):
Jon Hall4dbbbd62021-10-18 15:33:42 -0700285 executed = self.runStep( self.code, self.testCaseNumber )
286 if executed == self.FALSE:
287 # Skip the rest of the case if python error or SkipCase
adminbae64d82013-08-01 10:50:15 -0700288 break
Jon Hall4dbbbd62021-10-18 15:33:42 -0700289 elif executed == self.TRUE:
adminbae64d82013-08-01 10:50:15 -0700290 continue
Jon Hall5a72b712015-09-28 12:20:59 -0700291 # stepResults format: ( stepNo[], stepName[], stepResult[], onFail[] )
292 stepResults = self.stepResultsList
Jon Halle234cc42015-08-31 15:26:47 -0700293 if not stopped:
294 if self.CASERESULT == self.TRUE or self.CASERESULT == self.FALSE:
Jon Hall714eeba2015-09-29 17:53:10 -0700295 # Result was already explitily set somewhere else like
296 # in skipCase()
Jon Halle234cc42015-08-31 15:26:47 -0700297 pass
Jon Hall5a72b712015-09-28 12:20:59 -0700298 elif all( self.TRUE == i for i in stepResults ):
kelvin-onlabf70fd542015-05-07 18:41:40 -0700299 # ALL PASSED
300 self.CASERESULT = self.TRUE
Jon Hall5a72b712015-09-28 12:20:59 -0700301 elif self.FALSE in stepResults:
kelvin-onlabf70fd542015-05-07 18:41:40 -0700302 # AT LEAST ONE FAILED
303 self.CASERESULT = self.FALSE
Jon Hall5a72b712015-09-28 12:20:59 -0700304 elif self.TRUE in stepResults:
kelvin-onlabf70fd542015-05-07 18:41:40 -0700305 # AT LEAST ONE PASSED
306 self.CASERESULT = self.TRUE
307 else:
308 self.CASERESULT = self.NORESULT
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700309 self.testCaseResult[ str( self.CurrentTestCaseNumber ) ] = self.CASERESULT
Devin Limec989792017-08-15 15:57:55 -0700310 self.organizeResult( self.CurrentTestCaseNumber, self.CASERESULT )
Jon Hall714eeba2015-09-29 17:53:10 -0700311 self.logger.updateCaseResults( self )
Jon Hall783bbf92015-07-23 14:33:19 -0700312 self.log.summary( self.caseExplanation )
kelvin-onlabf70fd542015-05-07 18:41:40 -0700313 self.log.summary( self.stepCache )
Jon Hall026bd712021-08-31 16:30:09 -0700314 self.caseResultsWiki()
315 self.caseResultsTAP()
kelvin-onlabf70fd542015-05-07 18:41:40 -0700316 self.stepCache = ""
Jon Hall4dbbbd62021-10-18 15:33:42 -0700317 return executed
kelvin-onlabf70fd542015-05-07 18:41:40 -0700318
Jon Hall026bd712021-08-31 16:30:09 -0700319 def caseResultsWiki( self ):
320 """
321 Add case results to the wiki results file
322 """
323 self.log.wiki( "<p>" + self.caseExplanation + "</p>" )
324 self.log.wiki( "<ul>" )
325 subcaseMessage = False
326 for line in self.stepCache.splitlines():
327 if re.search( "[0-9]\.[0-9]", line ): # Step
328 if subcaseMessage: # End of Failure Message Printout
329 self.log.wiki( "</ul>\n" )
330 subcaseMessage = False
331 if re.search( " - PASS$", line ):
332 self.log.wiki( "<li>" + line + " <ac:emoticon ac:name=\"tick\" /></li>\n" )
333 elif re.search( " - FAIL$", line ):
334 self.log.wiki( "<li>" + line + " <ac:emoticon ac:name=\"cross\" /></li>\n" )
335 elif re.search( " - No Result$", line ):
336 self.log.wiki( "<li>" + line + " <ac:emoticon ac:name=\"warning\" /></li>\n" )
337 else: # Substep
338 if not subcaseMessage: # Open Failure Message Printout
339 self.log.wiki( "<ul><li>" + line + "</li>\n" )
340 subcaseMessage = True
341 else: # Add to Failure Message Printout
342 self.log.wiki( "<li>" + line + "</li>\n" )
343 if subcaseMessage: # End of Failure Message Printout for last item
344 self.log.wiki( "</ul>\n" )
345 self.log.wiki( "</ul>" )
346
347 def caseResultsTAP( self ):
348 """
349 Add case results to the TAP results file
350 """
Jon Hall026bd712021-08-31 16:30:09 -0700351 main.log.debug( self.stepCache )
Jon Hall026bd712021-08-31 16:30:09 -0700352 steps = 0
353 stepLines = []
354 for line in self.stepCache.splitlines():
Jon Hall026bd712021-08-31 16:30:09 -0700355 if re.search( "[0-9]\.[0-9]", line ): # Step
Jon Hall026bd712021-08-31 16:30:09 -0700356 if re.search( " - PASS$", line ):
357 steps += 1
Jon Halla8cf76a2021-10-05 14:31:47 -0700358 stepLines.append( " ok - STEP %s" % line )
Jon Hall026bd712021-08-31 16:30:09 -0700359 elif re.search( " - FAIL$", line ):
360 steps += 1
Jon Halla8cf76a2021-10-05 14:31:47 -0700361 stepLines.append( " not ok - STEP %s" % line )
Jon Hall026bd712021-08-31 16:30:09 -0700362 elif re.search( " - No Result$", line ):
363 steps += 1
Jon Halla8cf76a2021-10-05 14:31:47 -0700364 stepLines.append( " ok - STEP %s # TODO: No assertion in test step" % line )
Jon Hall026bd712021-08-31 16:30:09 -0700365 else: # Substep
Jon Halla8cf76a2021-10-05 14:31:47 -0700366 stepLines.append( " # %s" % line )
Jon Hall026bd712021-08-31 16:30:09 -0700367 if steps > 0:
368 self.log.TAP( " 1..%s" % steps )
Jon Halla8cf76a2021-10-05 14:31:47 -0700369 for line in stepLines:
370 self.log.TAP( line )
Jon Hall026bd712021-08-31 16:30:09 -0700371
Devin Limec989792017-08-15 15:57:55 -0700372 def organizeResult( self, caseNum, result ):
373 """
374 Organize the result and put the current number into either
375 failed/noResult lists.
376 * caseNum - number of the case
377 * result - result of the case
378 """
379 if result == main.FALSE:
380 self.failedCase.append( caseNum )
381 elif result == self.NORESULT:
382 self.noResultCase.append( caseNum )
383
Jon Hall714eeba2015-09-29 17:53:10 -0700384 def runStep( self, code, testCaseNumber ):
adminbae64d82013-08-01 10:50:15 -0700385 if not cli.pause:
Jon Hall5a72b712015-09-28 12:20:59 -0700386 try:
387 step = self.stepCount
388 # stepResults format: ( stepNo, stepName, stepResult, onFail )
389 # NOTE: This is needed to catch results of main.step()'s
390 # called inside functions or loops
391 self.stepResults = ( [], [], [], [] )
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700392 exec code[ testCaseNumber ][ step ] in module.__dict__
adminbae64d82013-08-01 10:50:15 -0700393 self.stepCount = self.stepCount + 1
Jon Hall96b816f2015-11-03 12:00:56 -0800394 self.parseStepResults( testCaseNumber )
Jon Hallca319892017-06-15 15:25:22 -0700395 except SkipCase: # Raised in self.skipCase()
Jon Halle234cc42015-08-31 15:26:47 -0700396 self.log.warn( "Skipping the rest of CASE" +
397 str( testCaseNumber ) )
Jon Hall96b816f2015-11-03 12:00:56 -0800398 self.parseStepResults( testCaseNumber )
Jon Hall714eeba2015-09-29 17:53:10 -0700399 self.stepResultsList.append( self.STEPRESULT )
Jon Halle234cc42015-08-31 15:26:47 -0700400 self.stepCache += "\t\t" + self.onFailMsg + "\n"
401 self.stepCount = self.stepCount + 1
402 return self.FALSE
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000403 except StandardError as e:
Jon Hall4dbbbd62021-10-18 15:33:42 -0700404 e_info = sys.exc_info()
Jon Hallc1606352015-10-06 14:51:36 -0700405 try:
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700406 stepNo = self.stepResults[ 0 ][ self.stepNumber - 1 ]
Jon Hallc1606352015-10-06 14:51:36 -0700407 except IndexError:
408 stepNo = "<IndexError>"
409 main.log.warn( "Error trying to get step number. " +
410 "It is likely between step " +
Jon Hall6e709752016-02-01 13:38:46 -0800411 str( self.stepNumber ) + " and step " +
Jon Hallc1606352015-10-06 14:51:36 -0700412 str( self.stepNumber + 1 ) )
413 try:
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700414 stepName = self.stepResults[ 1 ][ self.stepNumber - 1 ]
Jon Hallc1606352015-10-06 14:51:36 -0700415 except IndexError:
416 stepName = "<IndexError>"
Jon Hall4dbbbd62021-10-18 15:33:42 -0700417 errorMsg = "Exception in the following section of" +\
418 " code: " + str( testCaseNumber ) + "." +\
419 str( stepNo ) + ": " + stepName + "\n\t" +\
420 str( e.__class__ ) + str( e.message )
421 self.log.error( errorMsg, exc_info=e_info )
422 self.onFailMsg = errorMsg + ". Skipping the rest of this case. "
423 self.stepCache += "\t\t" + self.onFailMsg + "\n"
adminbae64d82013-08-01 10:50:15 -0700424 self.stepCount = self.stepCount + 1
Jon Hall4dbbbd62021-10-18 15:33:42 -0700425 self.testCaseResult[ str( self.CurrentTestCaseNumber ) ] = self.FALSE
426 self.organizeResult( self.CurrentTestCaseNumber, self.FALSE )
Jon Hall714eeba2015-09-29 17:53:10 -0700427 self.logger.updateCaseResults( self )
Jon Hall4dbbbd62021-10-18 15:33:42 -0700428 self.log.summary( self.caseExplanation )
kelvin-onlabf70fd542015-05-07 18:41:40 -0700429 self.log.summary( self.stepCache )
Jon Hall4dbbbd62021-10-18 15:33:42 -0700430 self.caseResultsWiki()
431 self.caseResultsTAP()
kelvin-onlabf70fd542015-05-07 18:41:40 -0700432 self.stepCache = ""
shahshreya957feaa2015-03-23 16:08:29 -0700433 self.cleanup()
Jon Hall00539b12015-04-03 13:55:46 -0700434 self.exit()
Jon Halle234cc42015-08-31 15:26:47 -0700435 return self.TRUE
adminbae64d82013-08-01 10:50:15 -0700436 if cli.stop:
437 cli.stop = False
adminbae64d82013-08-01 10:50:15 -0700438 self.TOTAL_TC_NORESULT = self.TOTAL_TC_NORESULT + 1
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700439 self.testCaseResult[ str( self.CurrentTestCaseNumber ) ] = "Stopped"
Jon Hall714eeba2015-09-29 17:53:10 -0700440 self.logger.updateCaseResults( self )
adminbae64d82013-08-01 10:50:15 -0700441 result = self.cleanup()
Jon Halle234cc42015-08-31 15:26:47 -0700442 return self.FALSE
443
Jon Hall026bd712021-08-31 16:30:09 -0700444 def stepResultsWiki( self ):
445 """
446 Add step results to the wiki file
447 """
448 # WIKI results
449 self.log.wiki( "<ul>" )
450 for line in self.stepCache.splitlines():
451 if re.search( " - PASS$", line ):
452 self.log.wiki( "<li>" + line + " <ac:emoticon ac:name=\"tick\" /></li>\n" )
453 elif re.search( " - FAIL$", line ):
454 self.log.wiki( "<li>" + line + " <ac:emoticon ac:name=\"cross\" /></li>\n" )
455 elif re.search( " - No Result$", line ):
456 self.log.wiki( "<li>" + line + " <ac:emoticon ac:name=\"warning\" /></li>\n" )
457 else: # Should only be on fail message
458 self.log.wiki( "<ul><li>" + line + "</li></ul>\n" )
459 self.log.wiki( "</ul>" )
460
461 def stepResultsTAP( self ):
462 """
463 Add step results to the TAP file
464 """
465 # TAP results
466 # TODO Do we need indetation for the steps?
467 main.log.debug( "StepResultsTAP" )
468 for line in self.stepCache.splitlines():
469 if re.search( " - PASS$", line ):
Jon Halla8cf76a2021-10-05 14:31:47 -0700470 self.log.TAP( " ok - STEP %s" % line )
Jon Hall026bd712021-08-31 16:30:09 -0700471 elif re.search( " - FAIL$", line ):
Jon Halla8cf76a2021-10-05 14:31:47 -0700472 self.log.TAP( " not ok - STEP %s" % line )
Jon Hall026bd712021-08-31 16:30:09 -0700473 elif re.search( " - No Result$", line ):
Jon Halla8cf76a2021-10-05 14:31:47 -0700474 self.log.TAP( " ok - STEP %s # TODO: No assertion in test step" % line )
Jon Hall026bd712021-08-31 16:30:09 -0700475 else: # Should only be on fail message
476 self.log.TAP( " # %s" % line )
477
Jon Hall96b816f2015-11-03 12:00:56 -0800478 def parseStepResults( self, testCaseNumber ):
479 """
480 Parse throught the step results for the wiki
481 """
482 try:
483 # Iterate through each of the steps and print them
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700484 for index in range( len( self.stepResults[ 0 ] ) ):
Jon Hall96b816f2015-11-03 12:00:56 -0800485 # stepResults = ( stepNo, stepName, stepResult, onFail )
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700486 stepNo = self.stepResults[ 0 ][ index ]
487 stepName = self.stepResults[ 1 ][ index ]
488 stepResult = self.stepResults[ 2 ][ index ]
489 onFail = self.stepResults[ 3 ][ index ]
Jon Hall96b816f2015-11-03 12:00:56 -0800490 self.stepCache += "\t" + str( testCaseNumber ) + "."
491 self.stepCache += str( stepNo ) + " "
492 self.stepCache += stepName + " - "
493 if stepResult == self.TRUE:
494 self.stepCache += "PASS\n"
495 elif stepResult == self.FALSE:
496 self.stepCache += "FAIL\n"
497 self.stepCache += "\t\t" + onFail + "\n"
498 else:
499 self.stepCache += "No Result\n"
500 self.stepResultsList.append( stepResult )
501 except Exception:
502 self.log.exception( "Error parsing step results" )
503
Jon Halla8cf76a2021-10-05 14:31:47 -0700504 def skipCase( self, result="NORESULT", msg=None ):
Jon Halle234cc42015-08-31 15:26:47 -0700505 """
506 Will skip the rest of the code in a test case. The case results will be
507 determined as normal based on completed assertions unless the result
508 argument is given.
509
510 Optional Arguments:
Jon Hall7c4f4302016-07-15 14:39:02 -0700511 result: Case insensitive string. Can be 'PASS' or 'FAIL' and will set
Jon Halle234cc42015-08-31 15:26:47 -0700512 the case result accordingly.
513 msg: Message to be printed when the case is skipped in the reports.
514 """
515 result = result.upper().strip()
516 if result == "PASS":
517 self.CASERESULT = self.TRUE
Jon Halla8cf76a2021-10-05 14:31:47 -0700518 elif result == "NORESULT":
519 self.CASERESULT = self.NORESULT
520 else:
Jon Halle234cc42015-08-31 15:26:47 -0700521 self.CASERESULT = self.FALSE
522 self.onFailMsg = "Skipping the rest of this case. "
523 if msg:
Jon Hall4dbbbd62021-10-18 15:33:42 -0700524 if isinstance( msg, Exception ):
525 self.onFailMsg += str( repr( msg ) )
526 else:
527 self.onFailMsg += str( msg )
Jon Hallca319892017-06-15 15:25:22 -0700528 raise SkipCase
kelvin-onlabf70fd542015-05-07 18:41:40 -0700529
Jon Hall714eeba2015-09-29 17:53:10 -0700530 def addCaseHeader( self ):
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700531 caseHeader = "\n" + "*" * 30 + "\n Result summary for Testcase" + \
Jon Hall714eeba2015-09-29 17:53:10 -0700532 str( self.CurrentTestCaseNumber ) + "\n" + "*" * 30 + "\n"
533 self.log.exact( caseHeader )
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700534 caseHeader = "\n" + "*" * 40 + "\nStart of Test Case" + \
Jon Hall714eeba2015-09-29 17:53:10 -0700535 str( self.CurrentTestCaseNumber ) + " : "
adminbae64d82013-08-01 10:50:15 -0700536 for driver in self.componentDictionary.keys():
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700537 vars( self )[ driver + 'log' ].info( caseHeader )
kelvin-onlabf70fd542015-05-07 18:41:40 -0700538
Jon Hall714eeba2015-09-29 17:53:10 -0700539 def addCaseFooter( self ):
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700540 stepNo = self.stepResults[ 0 ][ -2 ]
Jon Hall714eeba2015-09-29 17:53:10 -0700541 if stepNo > 0:
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700542 previousStep = " " + str( self.CurrentTestCaseNumber ) + "." + \
Jon Hall714eeba2015-09-29 17:53:10 -0700543 str( stepNo ) + ": " + str( self.stepName )
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700544 stepHeader = "\n" + "*" * 40 + "\nEnd of Step " + previousStep + \
Jon Hall714eeba2015-09-29 17:53:10 -0700545 "\n" + "*" * 40 + "\n"
kelvin-onlabf70fd542015-05-07 18:41:40 -0700546
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700547 caseFooter = "\n" + "*" * 40 + "\nEnd of Test case " + \
Jon Hall714eeba2015-09-29 17:53:10 -0700548 str( self.CurrentTestCaseNumber ) + "\n" + "*" * 40 + "\n"
kelvin-onlabf70fd542015-05-07 18:41:40 -0700549
adminbae64d82013-08-01 10:50:15 -0700550 for driver in self.driversList:
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700551 vars( self )[ driver ].write( stepHeader + "\n" + caseFooter )
adminbae64d82013-08-01 10:50:15 -0700552
Devin Limba37cdd2018-05-07 11:41:05 -0700553 def setCheckingPoint( self ):
554 '''
555 Using when running findPatchScript.sh. This function needs to be placed
556 on the point that has the problem.
557
558 For example, if you see unusual behavior or from the portion of the code,
559 this is where you need to put with the conditional statement.
560 If some of the latency result is much greater than usual, have if statement
561 that checks if the result is greater than some point and include this function.
562
563 This will mark the 0 to findPatchResult.txt in /tmp/ and exit the test.
564 Then from findPatchScript, it will move onto the next commit and re-run the
565 test.
566 '''
567 self.log.error( "Reached to the checking point. Will mark the result and exit the test" )
568 resultFile = open( "/tmp/findPatchResult.txt", "w" )
569 resultFile.write( "0" )
570 resultFile.close()
571 self.cleanAndExit()
572
Jon Hall714eeba2015-09-29 17:53:10 -0700573 def cleanup( self ):
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000574 '''
Jon Hall5b586732015-06-11 11:39:39 -0700575 Print a summary of the current test's results then attempt to release
576 all the component handles and the close opened file handles.
adminbae64d82013-08-01 10:50:15 -0700577
Jon Hall5b586732015-06-11 11:39:39 -0700578 This function shouldbe threadsafe such that cleanup will only be
579 executed once per test.
580
581 This will return TRUE if all the component handles and log handles
582 closed properly, else return FALSE.
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000583 '''
adminbae64d82013-08-01 10:50:15 -0700584 result = self.TRUE
Jon Hall5b586732015-06-11 11:39:39 -0700585 lock = self.cleanupLock
586 if lock.acquire( False ):
587 try:
588 if self.cleanupFlag is False: # First thread to run this
589 self.cleanupFlag = True
Jon Hall0fc0d452015-07-14 09:49:58 -0700590 if self.initiated:
Jon Hall714eeba2015-09-29 17:53:10 -0700591 self.logger.testSummary( self )
Jon Hall892818c2015-10-20 17:58:34 -0700592 components = self.componentDictionary
593 for component in sorted( components,
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700594 key=lambda item: components[ item ][ 'connect_order' ],
Jon Hall892818c2015-10-20 17:58:34 -0700595 reverse=True ):
Jon Hall714eeba2015-09-29 17:53:10 -0700596 try:
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700597 tempObject = vars( self )[ component ]
598 print "Disconnecting from " + str( tempObject.name ) + \
599 ": " + str( tempObject.__class__ )
Jon Hall5b586732015-06-11 11:39:39 -0700600 tempObject.disconnect()
Jon Hall1306a562015-09-04 11:21:24 -0700601 except KeyboardInterrupt:
602 pass
603 except KeyError:
604 # Component not created yet
605 self.log.warn( "Could not find the component " +
606 str( component ) )
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000607 except StandardError:
Jon Hall5b586732015-06-11 11:39:39 -0700608 self.log.exception( "Exception while disconnecting from " +
Jon Hall4dbbbd62021-10-18 15:33:42 -0700609 str( component ) )
Jon Hall5b586732015-06-11 11:39:39 -0700610 result = self.FALSE
611 # Closing all the driver's session files
612 for driver in self.componentDictionary.keys():
613 try:
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700614 vars( self )[ driver ].close_log_handles()
Jon Hall1306a562015-09-04 11:21:24 -0700615 except KeyboardInterrupt:
616 pass
617 except KeyError:
618 # Component not created yet
619 self.log.warn( "Could not find the component " +
620 str( driver ) + " while trying to" +
621 " close log file" )
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000622 except StandardError:
Jon Hall5b586732015-06-11 11:39:39 -0700623 self.log.exception( "Exception while closing log files for " +
Jon Hall4dbbbd62021-10-18 15:33:42 -0700624 str( driver ) )
Jon Hall5b586732015-06-11 11:39:39 -0700625 result = self.FALSE
626 else:
627 pass # Someone else already ran through this function
628 finally:
629 lock.release()
630 else: # Someone already has a lock
631 # NOTE: This could cause problems if we don't release the lock
632 # correctly
633 lock.acquire() # Wait for the other thread to finish
634 # NOTE: If we don't wait, exit could be called while the thread
635 # with the lock is still cleaning up
636 lock.release()
adminbae64d82013-08-01 10:50:15 -0700637 return result
Jon Halld61331b2015-02-17 16:35:47 -0800638
Jon Hall714eeba2015-09-29 17:53:10 -0700639 def pause( self ):
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000640 '''
Jon Hall714eeba2015-09-29 17:53:10 -0700641 This function will pause the test's execution, and will continue after
642 user provide 'resume' command.
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000643 '''
adminbae64d82013-08-01 10:50:15 -0700644 __builtin__.testthread.pause()
kelvin-onlabf70fd542015-05-07 18:41:40 -0700645
Jon Hall714eeba2015-09-29 17:53:10 -0700646 def onfail( self, *components ):
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000647 '''
kelvin-onlabf70fd542015-05-07 18:41:40 -0700648 When test step failed, calling all the components onfail.
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000649 '''
adminbae64d82013-08-01 10:50:15 -0700650 if not components:
Jon Hall714eeba2015-09-29 17:53:10 -0700651 try:
adminbae64d82013-08-01 10:50:15 -0700652 for component in self.componentDictionary.keys():
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700653 tempObject = vars( self )[ component ]
adminbae64d82013-08-01 10:50:15 -0700654 result = tempObject.onfail()
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000655 except StandardError as e:
Jon Hall714eeba2015-09-29 17:53:10 -0700656 print str( e )
adminbae64d82013-08-01 10:50:15 -0700657 result = self.FALSE
adminbae64d82013-08-01 10:50:15 -0700658 else:
Jon Hall714eeba2015-09-29 17:53:10 -0700659 try:
adminbae64d82013-08-01 10:50:15 -0700660 for component in components:
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700661 tempObject = vars( self )[ component ]
adminbae64d82013-08-01 10:50:15 -0700662 result = tempObject.onfail()
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000663 except StandardError as e:
Jon Hall714eeba2015-09-29 17:53:10 -0700664 print str( e )
adminbae64d82013-08-01 10:50:15 -0700665 result = self.FALSE
kelvin-onlabf70fd542015-05-07 18:41:40 -0700666
Jon Hall714eeba2015-09-29 17:53:10 -0700667 def getDriverPath( self, driverName ):
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000668 '''
Jon Hall714eeba2015-09-29 17:53:10 -0700669 Based on the component 'type' specified in the params , this method
670 will find the absolute path, by recursively searching the name of
671 the component.
672
673 NOTE: This function requires the linux 'find' command.
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000674 '''
adminbae64d82013-08-01 10:50:15 -0700675 import commands
676
Jon Hall714eeba2015-09-29 17:53:10 -0700677 cmd = "find " + drivers_path + " -name " + driverName + ".py"
678 result = commands.getoutput( cmd )
kelvin-onlabf70fd542015-05-07 18:41:40 -0700679
Jon Hall714eeba2015-09-29 17:53:10 -0700680 result_array = str( result ).split( '\n' )
adminbae64d82013-08-01 10:50:15 -0700681 result_count = 0
kelvin-onlabf70fd542015-05-07 18:41:40 -0700682
adminbae64d82013-08-01 10:50:15 -0700683 for drivers_list in result_array:
Jon Hall714eeba2015-09-29 17:53:10 -0700684 result_count = result_count + 1
685 if result_count > 1:
686 print "Found " + driverName + " " + str( result_count ) + " times:"
687 print str( result_array )
adminbae64d82013-08-01 10:50:15 -0700688 self.exit()
kelvin-onlabf70fd542015-05-07 18:41:40 -0700689
Jon Hall714eeba2015-09-29 17:53:10 -0700690 result = re.sub( "(.*)drivers", "", result )
691 result = re.sub( "\/\/", "/", result )
692 result = re.sub( "\.py", "", result )
693 result = re.sub( "\.pyc", "", result )
694 result = re.sub( "\/", ".", result )
695 result = "drivers" + result
adminbae64d82013-08-01 10:50:15 -0700696 return result
adminbae64d82013-08-01 10:50:15 -0700697
Jon Hall714eeba2015-09-29 17:53:10 -0700698 def step( self, stepDesc ):
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000699 '''
adminbae64d82013-08-01 10:50:15 -0700700 The step information of the test-case will append to the logs.
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000701 '''
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700702 previousStep = " " + str( self.CurrentTestCaseNumber ) + "." + \
Jon Hall714eeba2015-09-29 17:53:10 -0700703 str( self.stepNumber ) + ": " + str( self.stepName )
adminbae64d82013-08-01 10:50:15 -0700704 self.stepName = stepDesc
Jon Hall5a72b712015-09-28 12:20:59 -0700705 self.stepNumber += 1
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700706 self.stepResults[ 0 ].append( self.stepNumber )
707 self.stepResults[ 1 ].append( stepDesc )
708 self.stepResults[ 2 ].append( self.NORESULT )
709 self.stepResults[ 3 ].append( "No on fail message given" )
adminbae64d82013-08-01 10:50:15 -0700710
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700711 stepName = " " + str( self.CurrentTestCaseNumber ) + "." + \
Jon Hall714eeba2015-09-29 17:53:10 -0700712 str( self.stepNumber ) + ": " + str( stepDesc )
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700713 self.log.step( stepName )
adminbae64d82013-08-01 10:50:15 -0700714 stepHeader = ""
Jon Hall714eeba2015-09-29 17:53:10 -0700715 line = "\n" + "-" * 45 + "\n"
716 if self.stepNumber > 1:
717 stepHeader = line + "End of Step " + previousStep + line
718 stepHeader += line + "Start of Step" + stepName + line
adminbae64d82013-08-01 10:50:15 -0700719 for driver in self.componentDictionary.keys():
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700720 vars( self )[ driver + 'log' ].info( stepHeader )
kelvin-onlabf70fd542015-05-07 18:41:40 -0700721
Jon Hall714eeba2015-09-29 17:53:10 -0700722 def case( self, testCaseName ):
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000723 '''
adminbae64d82013-08-01 10:50:15 -0700724 Test's each test-case information will append to the logs.
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000725 '''
Jon Halld61331b2015-02-17 16:35:47 -0800726 self.CurrentTestCase = testCaseName
Jon Hall714eeba2015-09-29 17:53:10 -0700727 testCaseName = " " + str( testCaseName )
728 self.log.case( testCaseName )
729 caseHeader = testCaseName + "\n" + "*" * 40 + "\n"
adminbae64d82013-08-01 10:50:15 -0700730 for driver in self.componentDictionary.keys():
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700731 vars( self )[ driver + 'log' ].info( caseHeader )
kelvin-onlabf70fd542015-05-07 18:41:40 -0700732
Jon Hall714eeba2015-09-29 17:53:10 -0700733 def testDesc( self, description ):
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000734 '''
adminbae64d82013-08-01 10:50:15 -0700735 Test description will append to the logs.
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000736 '''
Jon Hall714eeba2015-09-29 17:53:10 -0700737 description = "Test Description : " + str( description )
738 self.log.info( description )
kelvin-onlabf70fd542015-05-07 18:41:40 -0700739
Jon Hall714eeba2015-09-29 17:53:10 -0700740 def _getTest( self ):
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000741 '''
Jon Hall714eeba2015-09-29 17:53:10 -0700742 This method will parse the test script to find required test
743 information.
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000744 '''
Jon Hall53c5e662016-04-13 16:06:56 -0700745 testFileHandler = open( main.testFile, 'r' )
adminbae64d82013-08-01 10:50:15 -0700746 testFileList = testFileHandler.readlines()
747 testFileHandler.close()
adminbae64d82013-08-01 10:50:15 -0700748 counter = 0
Jon Hall714eeba2015-09-29 17:53:10 -0700749 for index in range( len( testFileList ) ):
750 lineMatch = re.match( '\s+def CASE(\d+)(.*):',
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700751 testFileList[ index ],
Jon Hall714eeba2015-09-29 17:53:10 -0700752 0 )
adminbae64d82013-08-01 10:50:15 -0700753 if lineMatch:
Jon Hall714eeba2015-09-29 17:53:10 -0700754 counter = counter + 1
755 self.TC_PLANNED = len( self.testcases_list )
kelvin-onlabf70fd542015-05-07 18:41:40 -0700756
Jon Hall714eeba2015-09-29 17:53:10 -0700757 def response_parser( self, response, return_format ):
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000758 ''' It will load the default response parser '''
adminbae64d82013-08-01 10:50:15 -0700759 response_dict = {}
Jon Hall714eeba2015-09-29 17:53:10 -0700760 response_dict = self.response_to_dict( response, return_format )
761 return_format_string = self.dict_to_return_format( response,
762 return_format,
763 response_dict )
adminbae64d82013-08-01 10:50:15 -0700764 return return_format_string
kelvin-onlabf70fd542015-05-07 18:41:40 -0700765
Jon Hall714eeba2015-09-29 17:53:10 -0700766 def response_to_dict( self, response, return_format ):
adminbae64d82013-08-01 10:50:15 -0700767 response_dict = {}
Jon Hall714eeba2015-09-29 17:53:10 -0700768 json_match = re.search( '^\s*{', response )
769 xml_match = re.search( '^\s*\<', response )
770 ini_match = re.search( '^\s*\[', response )
771 if json_match:
772 self.log.info( "Response is in 'JSON' format, converting to '" +
773 return_format + "' format" )
Jon Halld61331b2015-02-17 16:35:47 -0800774 # Formatting the json string
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000775 response = re.sub( r"{\s*'?(\w)", r'{"\1', response )
Jon Hall714eeba2015-09-29 17:53:10 -0700776 response = re.sub( r",\s*'?(\w)", r',"\1', response )
777 response = re.sub( r"(\w)'?\s*:", r'\1":', response )
778 response = re.sub( r":\s*'(\w)'\s*([,}])", r':"\1"\2', response )
779 try:
adminbae64d82013-08-01 10:50:15 -0700780 import json
Jon Hall714eeba2015-09-29 17:53:10 -0700781 response_dict = json.loads( response )
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000782 except StandardError:
Jon Hall2a5002c2015-08-21 16:49:11 -0700783 self.log.exception( "Json Parser is unable to parse the string" )
adminbae64d82013-08-01 10:50:15 -0700784 return response_dict
Jon Hall714eeba2015-09-29 17:53:10 -0700785 elif ini_match:
786 self.log.info( "Response is in 'INI' format, converting to '" +
787 return_format + "' format" )
adminbae64d82013-08-01 10:50:15 -0700788 from configobj import ConfigObj
Jon Hall714eeba2015-09-29 17:53:10 -0700789 response_file = open( "respnse_file.temp", 'w' )
790 response_file.write( response )
Jon Halld61331b2015-02-17 16:35:47 -0800791 response_file.close()
Jon Hall714eeba2015-09-29 17:53:10 -0700792 response_dict = ConfigObj( "respnse_file.temp" )
adminbae64d82013-08-01 10:50:15 -0700793 return response_dict
Jon Hall714eeba2015-09-29 17:53:10 -0700794 elif xml_match:
795 self.log.info( "Response is in 'XML' format, converting to '" +
796 return_format + "' format" )
797 try:
798 response_dict = xmldict.xml_to_dict( "<response> " +
799 str( response ) +
800 " </response>" )
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000801 except StandardError:
Jon Hall1306a562015-09-04 11:21:24 -0700802 self.log.exception()
adminbae64d82013-08-01 10:50:15 -0700803 return response_dict
kelvin-onlabf70fd542015-05-07 18:41:40 -0700804
Jon Hall714eeba2015-09-29 17:53:10 -0700805 def dict_to_return_format( self, response, return_format, response_dict ):
806 if return_format == 'table':
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000807 ''' Will return in table format'''
adminbae64d82013-08-01 10:50:15 -0700808 to_do = "Call the table output formatter"
809 global response_table
810 response_table = '\n'
Jon Hall714eeba2015-09-29 17:53:10 -0700811 response_table = response_table + '\t'.join( response_dict ) + "\n"
kelvin-onlabf70fd542015-05-07 18:41:40 -0700812
Jon Hall714eeba2015-09-29 17:53:10 -0700813 def get_table( value_to_convert ):
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000814 ''' This will parse the dictionary recusrsively and print as
815 table format'''
adminbae64d82013-08-01 10:50:15 -0700816 table_data = ""
Jon Hall714eeba2015-09-29 17:53:10 -0700817 if isinstance( value_to_convert, dict ):
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700818 table_data = table_data + '\t'.join( value_to_convert ) + \
Jon Hall714eeba2015-09-29 17:53:10 -0700819 "\n"
820 for temp_val in value_to_convert.values():
821 table_data = table_data + get_table( temp_val )
822 else:
823 table_data = table_data + str( value_to_convert ) + "\t"
Jon Halld61331b2015-02-17 16:35:47 -0800824 return table_data
kelvin-onlabf70fd542015-05-07 18:41:40 -0700825
Jon Hall714eeba2015-09-29 17:53:10 -0700826 for value in response_dict.values():
827 response_table = response_table + get_table( value )
adminbae64d82013-08-01 10:50:15 -0700828 return response_table
kelvin-onlabf70fd542015-05-07 18:41:40 -0700829
Jon Hall714eeba2015-09-29 17:53:10 -0700830 elif return_format == 'config':
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000831 ''' Will return in config format'''
adminbae64d82013-08-01 10:50:15 -0700832 to_do = 'Call dict to config coverter'
Jon Hall714eeba2015-09-29 17:53:10 -0700833 response_string = str( response_dict )
adminbae64d82013-08-01 10:50:15 -0700834 print response_string
Jon Hall714eeba2015-09-29 17:53:10 -0700835 response_config = re.sub( ",", "\n\t", response_string )
836 response_config = re.sub( "u\'", "\'", response_config )
837 response_config = re.sub( "{", "", response_config )
838 response_config = re.sub( "}", "\n", response_config )
839 response_config = re.sub( ":", " =", response_config )
840 return "[response]\n\t " + response_config
adminbae64d82013-08-01 10:50:15 -0700841 elif return_format == 'xml':
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000842 ''' Will return in xml format'''
Jon Hall714eeba2015-09-29 17:53:10 -0700843 response_xml = xmldict.dict_to_xml( response_dict )
844 response_xml = re.sub( ">\s*<", ">\n<", response_xml )
845 return "\n" + response_xml
adminbae64d82013-08-01 10:50:15 -0700846 elif return_format == 'json':
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000847 ''' Will return in json format'''
adminbae64d82013-08-01 10:50:15 -0700848 to_do = 'Call dict to xml coverter'
849 import json
Jon Hall714eeba2015-09-29 17:53:10 -0700850 response_json = json.dumps( response_dict )
adminbae64d82013-08-01 10:50:15 -0700851 return response_json
kelvin-onlabf70fd542015-05-07 18:41:40 -0700852
Jon Hall714eeba2015-09-29 17:53:10 -0700853 def get_random( self ):
adminbae64d82013-08-01 10:50:15 -0700854 self.random_order = self.random_order + 1
855 return self.random_order
kelvin-onlabf70fd542015-05-07 18:41:40 -0700856
Jon Hall714eeba2015-09-29 17:53:10 -0700857 def exit( self ):
adminbae64d82013-08-01 10:50:15 -0700858 __builtin__.testthread = None
Jon Hall5b586732015-06-11 11:39:39 -0700859 for thread in threading.enumerate():
860 if thread.isAlive():
861 try:
862 thread._Thread__stop()
863 except:
Jon Hall1306a562015-09-04 11:21:24 -0700864 # NOTE: We should catch any exceptions while trying to
865 # close the thread so that we can try to close the other
866 # threads as well
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700867 print str( thread.getName() ) + \
Jon Hall714eeba2015-09-29 17:53:10 -0700868 ' could not be terminated'
Jeremy Ronquillo15ff1072017-07-17 10:55:46 -0700869 os.system( "stty sane" ) # fix format if necessary
adminbae64d82013-08-01 10:50:15 -0700870 sys.exit()
871
You Wang7880b372019-02-27 16:50:47 -0800872 def cleanAndExit( self, alarm=True, msg="" ):
Devin Lim44075962017-08-11 10:56:37 -0700873 """
874 It will set the testcase result to be FAILED and update it
875 before cleaning up and exitting the test.
You Wang7880b372019-02-27 16:50:47 -0800876 alarm: when set to True, it will write to the alarm log before
877 cleaning up and exitting; otherwise it will write to error log.
878 msg: message that will be written to the log if specified;
879 otherwise a default message will be written.
Devin Lim44075962017-08-11 10:56:37 -0700880 :return:
881 """
882 if self.CurrentTestCaseNumber:
883 self.testCaseResult[ str( self.CurrentTestCaseNumber ) ] = self.FALSE
Devin Limec989792017-08-15 15:57:55 -0700884 self.organizeResult( self.CurrentTestCaseNumber, self.FALSE )
Devin Lim44075962017-08-11 10:56:37 -0700885 self.logger.updateCaseResults( self )
You Wang7880b372019-02-27 16:50:47 -0800886 if alarm:
887 if msg:
888 self.log.alarm( "Test exited unexpectedly: {}".format( msg ) )
889 else:
890 self.log.alarm( "Test exited unexpectedly" )
891 else:
892 if msg:
893 self.log.error( "Test exited unexpectedly: {}".format( msg ) )
894 else:
895 self.log.error( "Test exited unexpectedly" )
Devin Lim44075962017-08-11 10:56:37 -0700896 self.cleanup()
897 self.exit()
Jeremy Ronquillo15ff1072017-07-17 10:55:46 -0700898
Jon Hallcd3d2a32015-10-01 11:07:28 -0700899 def stop( self, email=False ):
900 """
901 Stop the test until Ctrl-D is entered.
902 Ctrl-C will kill the test
Jon Hall25079782015-10-13 13:54:39 -0700903
904 Optional arguments:
905 email can either be a bool, or you can specify the email address
906 to send the email to
Jon Hallcd3d2a32015-10-01 11:07:28 -0700907 """
908 try:
909 if email:
Jon Hall25079782015-10-13 13:54:39 -0700910 if '@' in email:
911 main.mail = email
912 utilities.send_warning_email()
Jeremy Ronquillo15ff1072017-07-17 10:55:46 -0700913 self.log.debug( "Test execution suspended. \n"
914 "- Type 'c' to resume the test.\n"
915 "- Type Ctrl-C to exit the test.\n"
916 "- Enter interactive python interpreter commands.\n"
917 "\t- ie: main.Mininet1.pingall()\n"
918 "- Type 'help' for help with pdb." )
919 pdb.set_trace()
Jon Hallcd3d2a32015-10-01 11:07:28 -0700920 except EOFError:
921 return
922 # Pass all other exceptions up to caller
923
924
Jon Hall714eeba2015-09-29 17:53:10 -0700925def verifyOptions( options ):
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000926 '''
Jon Hall714eeba2015-09-29 17:53:10 -0700927 This will verify the command line options and set to default values,
928 if any option not given in command line.
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000929 '''
Jon Hall714eeba2015-09-29 17:53:10 -0700930 verifyTest( options )
931 verifyExample( options )
932 verifyTestScript( options )
YPZhang1c89e762016-06-29 10:43:58 -0700933 verifyParams( options )
Jon Hall714eeba2015-09-29 17:53:10 -0700934 verifyLogdir( options )
935 verifyMail( options )
936 verifyTestCases( options )
937 verifyOnosCell( options )
adminbae64d82013-08-01 10:50:15 -0700938
Jon Hall4dbbbd62021-10-18 15:33:42 -0700939
Jon Hall714eeba2015-09-29 17:53:10 -0700940def verifyTest( options ):
Jon Hall44506242015-07-29 17:40:26 -0700941 try:
942 if options.testname:
943 main.TEST = options.testname
Jon Hall714eeba2015-09-29 17:53:10 -0700944 main.classPath = "tests." + main.TEST + "." + main.TEST
Jon Hall44506242015-07-29 17:40:26 -0700945 main.tests_path = tests_path
946 elif options.example:
947 main.TEST = options.example
Jon Hall714eeba2015-09-29 17:53:10 -0700948 main.tests_path = path + "/examples/"
949 main.classPath = "examples." + main.TEST + "." + main.TEST
Jon Hall44506242015-07-29 17:40:26 -0700950 except AttributeError:
adminbae64d82013-08-01 10:50:15 -0700951 print "Test or Example not specified please specify the --test <test name > or --example <example name>"
Jon Hall5b586732015-06-11 11:39:39 -0700952 main.exit()
adminbae64d82013-08-01 10:50:15 -0700953
Jon Hall4dbbbd62021-10-18 15:33:42 -0700954
Jon Hall714eeba2015-09-29 17:53:10 -0700955def verifyExample( options ):
adminbae64d82013-08-01 10:50:15 -0700956 if options.example:
Jon Hall714eeba2015-09-29 17:53:10 -0700957 main.testDir = path + '/examples/'
958 main.tests_path = path + "/examples/"
959 main.classPath = "examples." + main.TEST + "." + main.TEST
kelvin-onlabf70fd542015-05-07 18:41:40 -0700960
Jon Hall4dbbbd62021-10-18 15:33:42 -0700961
Jon Hall714eeba2015-09-29 17:53:10 -0700962def verifyLogdir( options ):
Jon Hall88e498c2015-03-06 09:54:35 -0800963 # Verifying Log directory option
adminbae64d82013-08-01 10:50:15 -0700964 if options.logdir:
965 main.logdir = options.logdir
Jon Hall714eeba2015-09-29 17:53:10 -0700966 else:
Jon Halld61331b2015-02-17 16:35:47 -0800967 main.logdir = main.FALSE
kelvin-onlabf70fd542015-05-07 18:41:40 -0700968
Jon Hall4dbbbd62021-10-18 15:33:42 -0700969
Jon Hall714eeba2015-09-29 17:53:10 -0700970def verifyMail( options ):
Jon Hall25079782015-10-13 13:54:39 -0700971 # Mail-To: field
972 if options.mail: # Test run specific
adminbae64d82013-08-01 10:50:15 -0700973 main.mail = options.mail
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700974 elif main.params.get( 'mail' ): # Test suite specific
Jon Hall25079782015-10-13 13:54:39 -0700975 main.mail = main.params.get( 'mail' )
976 else: # TestON specific
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700977 main.mail = main.config[ 'config' ].get( 'mail_to' )
Jon Hall25079782015-10-13 13:54:39 -0700978 # Mail-From: field
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700979 main.sender = main.config[ 'config' ].get( 'mail_from' )
Jon Hall25079782015-10-13 13:54:39 -0700980 # Mail smtp server
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700981 main.smtp = main.config[ 'config' ].get( 'mail_server' )
Jon Hall25079782015-10-13 13:54:39 -0700982 # Mail-From account password
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700983 main.senderPwd = main.config[ 'config' ].get( 'mail_pass' )
Jon Hall25079782015-10-13 13:54:39 -0700984
Jon Hall4dbbbd62021-10-18 15:33:42 -0700985
Devin Lim2df68a12017-06-30 15:39:05 -0700986def evalTestCase( tempList ):
987 tList = []
988 for tcase in tempList:
989 if isinstance( tcase, list ):
990 tList.extend( evalTestCase( tcase ) )
991 else:
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700992 tList.extend( [ tcase ] )
Devin Lim2df68a12017-06-30 15:39:05 -0700993 return tList
adminbae64d82013-08-01 10:50:15 -0700994
Jon Hall4dbbbd62021-10-18 15:33:42 -0700995
Jon Hall714eeba2015-09-29 17:53:10 -0700996def verifyTestCases( options ):
Jon Hall88e498c2015-03-06 09:54:35 -0800997 # Getting Test cases list
adminbae64d82013-08-01 10:50:15 -0700998 if options.testcases:
Jon Hall714eeba2015-09-29 17:53:10 -0700999 testcases_list = re.sub( "(\[|\])", "", options.testcases )
1000 main.testcases_list = eval( testcases_list + "," )
1001 else:
adminbae64d82013-08-01 10:50:15 -07001002 if 'testcases' in main.params.keys():
Jeremy Ronquillo696f4262017-10-17 10:56:26 -07001003 temp = eval( main.params[ 'testcases' ] + "," )
Devin Lim2df68a12017-06-30 15:39:05 -07001004 main.testcases_list = evalTestCase( list( temp ) )
Jon Hall714eeba2015-09-29 17:53:10 -07001005 else:
Jeremy Ronquillo696f4262017-10-17 10:56:26 -07001006 print "Testcases not specifed in params, please provide in " + \
Jon Hall714eeba2015-09-29 17:53:10 -07001007 "params file or 'testcases' commandline argument"
Jon Halld61331b2015-02-17 16:35:47 -08001008 sys.exit()
kelvin-onlabf70fd542015-05-07 18:41:40 -07001009
Jon Hall4dbbbd62021-10-18 15:33:42 -07001010
Jon Hall714eeba2015-09-29 17:53:10 -07001011def verifyOnosCell( options ):
Hari Krishnabe4b97b2015-07-15 12:19:43 -07001012 # Verifying onoscell option
Hari Krishna03f530e2015-07-10 17:28:27 -07001013 if options.onoscell:
1014 main.onoscell = options.onoscell
Devin Lim58046fa2017-07-05 16:55:00 -07001015 main.ONOSip = []
Hari Krishnabe4b97b2015-07-15 12:19:43 -07001016 main.mnIP = ""
Devin Lim58046fa2017-07-05 16:55:00 -07001017 cellCMD = ". ~/onos/tools/dev/bash_profile; cell " + main.onoscell
Jeremy Ronquillo696f4262017-10-17 10:56:26 -07001018 output = subprocess.check_output( [ "bash", '-c', cellCMD ] )
Hari Krishnabe4b97b2015-07-15 12:19:43 -07001019 splitOutput = output.splitlines()
Devin Lim58046fa2017-07-05 16:55:00 -07001020 main.apps = ""
Jon Hall714eeba2015-09-29 17:53:10 -07001021 for i in range( len( splitOutput ) ):
Jeremy Ronquillo696f4262017-10-17 10:56:26 -07001022 if re.match( "OCN", splitOutput[ i ] ):
1023 mnNode = splitOutput[ i ].split( "=" )
1024 main.mnIP = mnNode[ 1 ]
Jon Hall714eeba2015-09-29 17:53:10 -07001025 # cell already sorts OC variables in bash, so no need to
1026 # sort in TestON
Jeremy Ronquillo696f4262017-10-17 10:56:26 -07001027 elif re.match( "OC[1-9]", splitOutput[ i ] ):
1028 onosNodes = splitOutput[ i ].split( "=" )
1029 main.ONOSip.append( onosNodes[ 1 ] )
1030 elif re.match( "ONOS_APPS", splitOutput[ i ] ):
1031 main.apps = ( splitOutput[ i ].split( "=" ) )[ 1 ]
Jon Hall714eeba2015-09-29 17:53:10 -07001032 else:
Hari Krishna03f530e2015-07-10 17:28:27 -07001033 main.onoscell = main.FALSE
1034
Jon Hall4dbbbd62021-10-18 15:33:42 -07001035
Jon Hall714eeba2015-09-29 17:53:10 -07001036def verifyTestScript( options ):
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +00001037 '''
adminbae64d82013-08-01 10:50:15 -07001038 Verifyies test script.
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +00001039 '''
Jon Halld61331b2015-02-17 16:35:47 -08001040 main.openspeak = openspeak.OpenSpeak()
Jon Hall53c5e662016-04-13 16:06:56 -07001041 directory = main.testDir + "/" + main.TEST
1042 if os.path.exists( directory ):
1043 pass
1044 else:
1045 directory = ""
Jeremy Ronquillo696f4262017-10-17 10:56:26 -07001046 for root, dirs, files in os.walk( main.testDir, topdown=True ):
Jon Hall53c5e662016-04-13 16:06:56 -07001047 if not directory:
1048 for name in dirs:
1049 if name == main.TEST:
1050 directory = ( os.path.join( root, name ) )
1051 index = directory.find( "/tests/" ) + 1
Jeremy Ronquillo696f4262017-10-17 10:56:26 -07001052 main.classPath = directory[ index: ].replace( '/', '.' ) + "." + main.TEST
Jon Hall53c5e662016-04-13 16:06:56 -07001053 break
1054 openspeakfile = directory + "/" + main.TEST + ".ospk"
Jon Halld74d2952018-03-01 13:26:39 -08001055 main.testDir = directory
Jon Hall53c5e662016-04-13 16:06:56 -07001056 main.testFile = directory + "/" + main.TEST + ".py"
Jon Hall714eeba2015-09-29 17:53:10 -07001057 if os.path.exists( openspeakfile ):
Jon Hall44506242015-07-29 17:40:26 -07001058 # Openspeak file found, compiling to python
Jon Hall714eeba2015-09-29 17:53:10 -07001059 main.openspeak.compiler( openspeakfile=openspeakfile, writetofile=1 )
Jon Hall53c5e662016-04-13 16:06:56 -07001060 elif os.path.exists( main.testFile ):
Jon Hall44506242015-07-29 17:40:26 -07001061 # No openspeak found, using python file instead
1062 pass
adminbae64d82013-08-01 10:50:15 -07001063 else:
Jeremy Ronquillo696f4262017-10-17 10:56:26 -07001064 print "\nThere is no \"" + main.TEST + "\" test script.\nPlease provide a " + \
1065 "Python or OpenSpeak test script in the tests folder: " + \
Jon Hall714eeba2015-09-29 17:53:10 -07001066 main.testDir + "/" + main.TEST + "/"
adminbae64d82013-08-01 10:50:15 -07001067 __builtin__.testthread = None
1068 main.exit()
Jon Hall714eeba2015-09-29 17:53:10 -07001069 try:
1070 testModule = __import__( main.classPath,
1071 globals(),
1072 locals(),
Jeremy Ronquillo696f4262017-10-17 10:56:26 -07001073 [ main.TEST ],
Jon Hall714eeba2015-09-29 17:53:10 -07001074 -1 )
Jon Hall1306a562015-09-04 11:21:24 -07001075 except ImportError:
Jeremy Ronquillo696f4262017-10-17 10:56:26 -07001076 print "There was an import error, it might mean that there is " + \
Jon Hall714eeba2015-09-29 17:53:10 -07001077 "no test named " + main.TEST
Jon Halld61331b2015-02-17 16:35:47 -08001078 main.exit()
adminbae64d82013-08-01 10:50:15 -07001079
Jon Hall714eeba2015-09-29 17:53:10 -07001080 testClass = getattr( testModule, main.TEST )
adminbae64d82013-08-01 10:50:15 -07001081 main.testObject = testClass()
1082 load_parser()
Jon Halld74d2952018-03-01 13:26:39 -08001083 main.paramsFile = main.TEST + ".params" if options.paramsFile is None else options.paramsFile
1084 main.topoFile = main.TEST + ".topo" if options.topoFile is None else options.topoFile
1085 main.params = main.parser.parseFile( main.testDir + "/" + main.paramsFile )
1086 main.topology = main.parser.parseFile( main.testDir + "/" + main.topoFile )
kelvin-onlabf70fd542015-05-07 18:41:40 -07001087
Jon Hall4dbbbd62021-10-18 15:33:42 -07001088
YPZhang1c89e762016-06-29 10:43:58 -07001089def verifyParams( options ):
Jon Hall714eeba2015-09-29 17:53:10 -07001090 try:
Jeremy Ronquillo696f4262017-10-17 10:56:26 -07001091 main.params = main.params[ 'PARAMS' ]
Jon Hall1306a562015-09-04 11:21:24 -07001092 except KeyError:
Jeremy Ronquillo696f4262017-10-17 10:56:26 -07001093 print "Error with the params file: Either the file not specified " + \
Jon Hall714eeba2015-09-29 17:53:10 -07001094 "or the format is not correct"
Jon Halld61331b2015-02-17 16:35:47 -08001095 main.exit()
Jon Hall714eeba2015-09-29 17:53:10 -07001096 try:
Jeremy Ronquillo696f4262017-10-17 10:56:26 -07001097 main.topology = main.topology[ 'TOPOLOGY' ]
Jon Hall1306a562015-09-04 11:21:24 -07001098 except KeyError:
Jeremy Ronquillo696f4262017-10-17 10:56:26 -07001099 print "Error with the Topology file: Either the file not specified " + \
Jon Hall714eeba2015-09-29 17:53:10 -07001100 "or the format is not correct"
adminbae64d82013-08-01 10:50:15 -07001101 main.exit()
YPZhang1c89e762016-06-29 10:43:58 -07001102 # Overwrite existing params variables if they are specified from command line
Jeremy Ronquillo696f4262017-10-17 10:56:26 -07001103 if len( options.params ) > 0:
YPZhang1c89e762016-06-29 10:43:58 -07001104 # Some params variables are specified from command line
1105 for param in options.params:
1106 if not re.search( ".=.", param ):
1107 print( "Error when parsing params: params should follow key=value format" )
1108 continue
Jon Hall7c4f4302016-07-15 14:39:02 -07001109 # Split the param string to catch nested keys and the value
YPZhang1c89e762016-06-29 10:43:58 -07001110 [ keys, value ] = param.split( "=" )
1111 # Split the nested keys according to its hierarchy
1112 keyList = keys.split( "/" )
1113 # Get the outermost dictionary
1114 paramDict = main.params
1115 # Get the innermost dictionary
1116 try:
1117 while len( keyList ) > 1:
Jeremy Ronquillo696f4262017-10-17 10:56:26 -07001118 key = keyList.pop( 0 )
YPZhang1c89e762016-06-29 10:43:58 -07001119 assert isinstance( paramDict[ key ], dict )
1120 paramDict = paramDict[ key ]
1121 except KeyError:
1122 print( "Error when parsing params: key \"" + key + "\" not found in main.params" )
1123 main.exit()
1124 except AssertionError:
1125 print( "Error when parsing params: \"" + key + "\" is already the innermost level in main.params" )
1126 main.exit()
1127 # Change the value
Jeremy Ronquillo696f4262017-10-17 10:56:26 -07001128 if keyList[ 0 ] not in paramDict:
1129 print( "Error when parsing params: key \"" + keyList[ 0 ] + "\" not found in main.params" )
YPZhang1c89e762016-06-29 10:43:58 -07001130 main.exit()
Jeremy Ronquillo696f4262017-10-17 10:56:26 -07001131 elif isinstance( paramDict[ keyList[ 0 ] ], dict ):
1132 print( "Error when parsing params: more levels under key \"" + keyList[ 0 ] + "\" in main.params" )
YPZhang1c89e762016-06-29 10:43:58 -07001133 main.exit()
1134 else:
Jeremy Ronquillo696f4262017-10-17 10:56:26 -07001135 paramDict[ keyList[ 0 ] ] = value
kelvin-onlabf70fd542015-05-07 18:41:40 -07001136
Jon Hall4dbbbd62021-10-18 15:33:42 -07001137
Jon Hall714eeba2015-09-29 17:53:10 -07001138def load_parser():
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +00001139 '''
adminbae64d82013-08-01 10:50:15 -07001140 It facilitates the loading customised parser for topology and params file.
1141 It loads parser mentioned in tab named parser of teston.cfg file.
Jon Hall714eeba2015-09-29 17:53:10 -07001142 It also loads default xmlparser if no parser have specified in teston.cfg
1143 file.
adminbae64d82013-08-01 10:50:15 -07001144
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +00001145 '''
adminbae64d82013-08-01 10:50:15 -07001146 confighash = main.configDict
Jeremy Ronquillo696f4262017-10-17 10:56:26 -07001147 if 'file' in confighash[ 'config' ][ 'parser' ] and\
1148 'class' in confighash[ 'config' ][ 'parser' ]:
1149 path = confighash[ 'config' ][ 'parser' ][ 'file' ]
Jon Hall714eeba2015-09-29 17:53:10 -07001150 if path is not None or\
Jeremy Ronquillo696f4262017-10-17 10:56:26 -07001151 confighash[ 'config' ][ 'parser' ][ 'class' ] is not None:
Jon Hall44506242015-07-29 17:40:26 -07001152 try:
1153 module = re.sub( r".py\s*$", "", path )
Jeremy Ronquillo696f4262017-10-17 10:56:26 -07001154 moduleList = module.split( "/" )
1155 newModule = ".".join( moduleList[ -2: ] )
1156 parsingClass = confighash[ 'config' ][ 'parser' ][ 'class' ]
Jon Hall714eeba2015-09-29 17:53:10 -07001157 parsingModule = __import__( newModule,
1158 globals(),
1159 locals(),
Jeremy Ronquillo696f4262017-10-17 10:56:26 -07001160 [ parsingClass ],
Jon Hall714eeba2015-09-29 17:53:10 -07001161 -1 )
1162 parsingClass = getattr( parsingModule, parsingClass )
Jon Hall44506242015-07-29 17:40:26 -07001163 main.parser = parsingClass()
Jon Halld74d2952018-03-01 13:26:39 -08001164 if hasattr( main.parser, "parseFile" ) and\
Jon Hall714eeba2015-09-29 17:53:10 -07001165 hasattr( main.parser, "parse" ):
Jon Hall44506242015-07-29 17:40:26 -07001166 pass
1167 else:
1168 print "Invalid parser format"
adminbae64d82013-08-01 10:50:15 -07001169 main.exit()
Jon Hall44506242015-07-29 17:40:26 -07001170 except ImportError:
Jeremy Ronquillo696f4262017-10-17 10:56:26 -07001171 print "Could not find the file " + path + \
Jon Hall714eeba2015-09-29 17:53:10 -07001172 " using default parser."
Jon Halld61331b2015-02-17 16:35:47 -08001173 load_defaultParser()
Jeremy Ronquillo696f4262017-10-17 10:56:26 -07001174 elif confighash[ 'config' ][ 'parser' ][ 'file' ] is None or\
1175 confighash[ 'config' ][ 'parser' ][ 'class' ] is None:
Jon Halld61331b2015-02-17 16:35:47 -08001176 load_defaultParser()
adminbae64d82013-08-01 10:50:15 -07001177 else:
1178 load_defaultParser()
1179
1180def load_defaultParser():
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +00001181 '''
Jon Hall714eeba2015-09-29 17:53:10 -07001182 It will load the default parser which is xml parser to parse the params and
1183 topology file.
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +00001184 '''
Jeremy Ronquillo696f4262017-10-17 10:56:26 -07001185 moduleList = main.parserPath.split( "/" )
1186 newModule = ".".join( moduleList[ -2: ] )
Jon Hall714eeba2015-09-29 17:53:10 -07001187 try:
Jon Halld61331b2015-02-17 16:35:47 -08001188 parsingClass = main.parsingClass
Jon Hall714eeba2015-09-29 17:53:10 -07001189 parsingModule = __import__( newModule,
1190 globals(),
1191 locals(),
Jeremy Ronquillo696f4262017-10-17 10:56:26 -07001192 [ parsingClass ],
Jon Hall714eeba2015-09-29 17:53:10 -07001193 -1 )
1194 parsingClass = getattr( parsingModule, parsingClass )
adminbae64d82013-08-01 10:50:15 -07001195 main.parser = parsingClass()
Jon Halld74d2952018-03-01 13:26:39 -08001196 if hasattr( main.parser, "parseFile" ) and\
Jon Hall714eeba2015-09-29 17:53:10 -07001197 hasattr( main.parser, "parse" ):
adminbae64d82013-08-01 10:50:15 -07001198 pass
1199 else:
1200 main.exit()
adminbae64d82013-08-01 10:50:15 -07001201 except ImportError:
Jeremy Ronquillo696f4262017-10-17 10:56:26 -07001202 print sys.exc_info()[ 1 ]
adminbae64d82013-08-01 10:50:15 -07001203
Jon Hall4dbbbd62021-10-18 15:33:42 -07001204
Jon Hall714eeba2015-09-29 17:53:10 -07001205def load_logger():
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +00001206 '''
adminbae64d82013-08-01 10:50:15 -07001207 It facilitates the loading customised parser for topology and params file.
1208 It loads parser mentioned in tab named parser of teston.cfg file.
Jon Hall714eeba2015-09-29 17:53:10 -07001209 It also loads default xmlparser if no parser have specified in teston.cfg
1210 file.
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +00001211 '''
adminbae64d82013-08-01 10:50:15 -07001212 confighash = main.configDict
Jeremy Ronquillo696f4262017-10-17 10:56:26 -07001213 if 'file' in confighash[ 'config' ][ 'logger' ] and\
1214 'class' in confighash[ 'config' ][ 'logger' ]:
1215 path = confighash[ 'config' ][ 'logger' ][ 'file' ]
Jon Hall714eeba2015-09-29 17:53:10 -07001216 if path is not None or\
Jeremy Ronquillo696f4262017-10-17 10:56:26 -07001217 confighash[ 'config' ][ 'logger' ][ 'class' ] is not None:
Jon Hall44506242015-07-29 17:40:26 -07001218 try:
1219 module = re.sub( r".py\s*$", "", path )
Jon Hall714eeba2015-09-29 17:53:10 -07001220 moduleList = module.split( "/" )
Jeremy Ronquillo696f4262017-10-17 10:56:26 -07001221 newModule = ".".join( moduleList[ -2: ] )
1222 loggerClass = confighash[ 'config' ][ 'logger' ][ 'class' ]
Jon Hall714eeba2015-09-29 17:53:10 -07001223 loggerModule = __import__( newModule,
1224 globals(),
1225 locals(),
Jeremy Ronquillo696f4262017-10-17 10:56:26 -07001226 [ loggerClass ],
Jon Hall714eeba2015-09-29 17:53:10 -07001227 -1 )
1228 loggerClass = getattr( loggerModule, loggerClass )
Jon Hall44506242015-07-29 17:40:26 -07001229 main.logger = loggerClass()
Jon Hall44506242015-07-29 17:40:26 -07001230 except ImportError:
Jeremy Ronquillo696f4262017-10-17 10:56:26 -07001231 print "Could not find the file " + path + \
Jon Hall714eeba2015-09-29 17:53:10 -07001232 " using default logger."
adminbae64d82013-08-01 10:50:15 -07001233 load_defaultlogger()
Jeremy Ronquillo696f4262017-10-17 10:56:26 -07001234 elif confighash[ 'config' ][ 'parser' ][ 'file' ] is None or\
1235 confighash[ 'config' ][ 'parser' ][ 'class' ] is None:
Jon Halld61331b2015-02-17 16:35:47 -08001236 load_defaultlogger()
adminbae64d82013-08-01 10:50:15 -07001237 else:
1238 load_defaultlogger()
1239
Jon Hall4dbbbd62021-10-18 15:33:42 -07001240
adminbae64d82013-08-01 10:50:15 -07001241def load_defaultlogger():
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +00001242 '''
Jon Hall714eeba2015-09-29 17:53:10 -07001243 It will load the default parser which is xml parser to parse the params and
1244 topology file.
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +00001245 '''
Jeremy Ronquillo696f4262017-10-17 10:56:26 -07001246 moduleList = main.loggerPath.split( "/" )
1247 newModule = ".".join( moduleList[ -2: ] )
Jon Hall714eeba2015-09-29 17:53:10 -07001248 try:
Jon Halld61331b2015-02-17 16:35:47 -08001249 loggerClass = main.loggerClass
Jon Hall714eeba2015-09-29 17:53:10 -07001250 loggerModule = __import__( newModule,
1251 globals(),
1252 locals(),
Jeremy Ronquillo696f4262017-10-17 10:56:26 -07001253 [ loggerClass ],
Jon Hall714eeba2015-09-29 17:53:10 -07001254 -1 )
1255 loggerClass = getattr( loggerModule, loggerClass )
adminbae64d82013-08-01 10:50:15 -07001256 main.logger = loggerClass()
1257
1258 except ImportError:
Jeremy Ronquillo696f4262017-10-17 10:56:26 -07001259 print sys.exc_info()[ 1 ]
Jon Halld61331b2015-02-17 16:35:47 -08001260 main.exit()
adminbae64d82013-08-01 10:50:15 -07001261
Jon Hall4dbbbd62021-10-18 15:33:42 -07001262
Jon Hall714eeba2015-09-29 17:53:10 -07001263def _echo( self ):
adminbae64d82013-08-01 10:50:15 -07001264 print "THIS IS ECHO"