blob: a7704902b83cb360e7093314f68227ba86e3f7f9 [file] [log] [blame]
adminbae64d82013-08-01 10:50:15 -07001#!/usr/bin/env python
2'''
3Created on 22-Oct-2012
Jon Hall65844a32015-03-09 19:09:37 -07004
adminbae64d82013-08-01 10:50:15 -07005@author: Anil Kumar (anilkumar.s@paxterrasolutions.com)
6
7
8 TestON is free software: you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 2 of the License, or
11 (at your option) any later version.
12
13 TestON is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
Jon Hall65844a32015-03-09 19:09:37 -070019 along with TestON. If not, see <http://www.gnu.org/licenses/>.
adminbae64d82013-08-01 10:50:15 -070020
21
22
23teston is the main module.
24
25'''
26
27import sys
28import getpass
29import os
30import re
31import __builtin__
32import new
33import xmldict
Jon Hall30b82fa2015-03-04 17:15:43 -080034import importlib
Jon Hall5b586732015-06-11 11:39:39 -070035import threading
Jon Hall714eeba2015-09-29 17:53:10 -070036module = new.module( "test" )
adminbae64d82013-08-01 10:50:15 -070037import openspeak
Hari Krishnabe4b97b2015-07-15 12:19:43 -070038import subprocess
Jon Hall714eeba2015-09-29 17:53:10 -070039global path, drivers_path, core_path, tests_path, logs_path
Jon Hall44506242015-07-29 17:40:26 -070040location = os.path.abspath( os.path.dirname( __file__ ) )
41path = re.sub( "(core|bin)$", "", location )
Jon Hall714eeba2015-09-29 17:53:10 -070042drivers_path = path + "drivers"
43core_path = path + "core"
44tests_path = path + "tests"
45logs_path = path + "logs/"
adminbae64d82013-08-01 10:50:15 -070046config_path = path + "config/"
Jon Hall44506242015-07-29 17:40:26 -070047sys.path.append( path )
48sys.path.append( drivers_path )
49sys.path.append( core_path )
50sys.path.append( tests_path )
adminbae64d82013-08-01 10:50:15 -070051
52from core.utilities import Utilities
kelvin-onlabfb521662015-02-27 09:52:40 -080053from core.Thread import Thread
adminbae64d82013-08-01 10:50:15 -070054
adminbae64d82013-08-01 10:50:15 -070055
56class TestON:
57 '''
kelvin-onlabf70fd542015-05-07 18:41:40 -070058 TestON will initiate the specified test.
Jon Hall714eeba2015-09-29 17:53:10 -070059 The main tasks are:
kelvin-onlabf70fd542015-05-07 18:41:40 -070060 * Initiate the required Component handles for the test.
adminbae64d82013-08-01 10:50:15 -070061 * Create Log file Handles.
adminbae64d82013-08-01 10:50:15 -070062 '''
Jon Hall714eeba2015-09-29 17:53:10 -070063 def __init__( self, options ):
adminbae64d82013-08-01 10:50:15 -070064 '''
Jon Hall714eeba2015-09-29 17:53:10 -070065 Initialise the component handles specified in the topology file of
66 the specified test.
adminbae64d82013-08-01 10:50:15 -070067 '''
68 # Initialization of the variables.
69 __builtin__.main = self
adminbae64d82013-08-01 10:50:15 -070070 __builtin__.path = path
71 __builtin__.utilities = Utilities()
72 self.TRUE = 1
73 self.FALSE = 0
74 self.ERROR = -1
kelvin-onlabf70fd542015-05-07 18:41:40 -070075 self.NORESULT = 2
adminbae64d82013-08-01 10:50:15 -070076 self.FAIL = False
77 self.PASS = True
kelvin-onlabf70fd542015-05-07 18:41:40 -070078 self.CASERESULT = self.ERROR
79 self.STEPRESULT = self.NORESULT
adminbae64d82013-08-01 10:50:15 -070080 self.init_result = self.TRUE
81 self.testResult = "Summary"
kelvin-onlabf70fd542015-05-07 18:41:40 -070082 self.stepName = ""
83 self.stepCache = ""
Jon Halld61331b2015-02-17 16:35:47 -080084 self.EXPERIMENTAL_MODE = False
adminbae64d82013-08-01 10:50:15 -070085 self.test_target = None
86 self.lastcommand = None
Jon Halld61331b2015-02-17 16:35:47 -080087 self.testDir = tests_path
88 self.configFile = config_path + "teston.cfg"
adminbae64d82013-08-01 10:50:15 -070089 self.parsingClass = "xmlparser"
90 self.parserPath = core_path + "/xmlparser"
91 self.loggerPath = core_path + "/logger"
92 self.loggerClass = "Logger"
93 self.logs_path = logs_path
94 self.driver = ''
kelvin-onlabfb521662015-02-27 09:52:40 -080095 self.Thread = Thread
Jon Hall5b586732015-06-11 11:39:39 -070096 self.cleanupFlag = False
97 self.cleanupLock = threading.Lock()
Jon Hall0fc0d452015-07-14 09:49:58 -070098 self.initiated = False
Jon Hall65844a32015-03-09 19:09:37 -070099
Jon Hall25079782015-10-13 13:54:39 -0700100 self.config = self.configparser()
Jon Hall714eeba2015-09-29 17:53:10 -0700101 verifyOptions( options )
adminbae64d82013-08-01 10:50:15 -0700102 load_logger()
103 self.componentDictionary = {}
Jon Hall714eeba2015-09-29 17:53:10 -0700104 self.componentDictionary = self.topology['COMPONENT']
105 self.driversList = []
106 if isinstance( self.componentDictionary, str):
107 self.componentDictionary = dict( self.componentDictionary )
Jon Hall65844a32015-03-09 19:09:37 -0700108
Jon Hall714eeba2015-09-29 17:53:10 -0700109 for component in self.componentDictionary:
110 self.driversList.append( self.componentDictionary[component]['type'] )
Jon Hall65844a32015-03-09 19:09:37 -0700111
Jon Hall714eeba2015-09-29 17:53:10 -0700112 self.driversList = list( set( self.driversList ) ) # Removing duplicates.
adminbae64d82013-08-01 10:50:15 -0700113 # Checking the test_target option set for the component or not
Jon Hall714eeba2015-09-29 17:53:10 -0700114 if isinstance( self.componentDictionary, dict ):
adminbae64d82013-08-01 10:50:15 -0700115 for component in self.componentDictionary.keys():
116 if 'test_target' in self.componentDictionary[component].keys():
117 self.test_target = component
Jon Hall65844a32015-03-09 19:09:37 -0700118
Jon Halld61331b2015-02-17 16:35:47 -0800119 # Checking for the openspeak file and test script
Jon Hall714eeba2015-09-29 17:53:10 -0700120 self.logger.initlog( self )
adminbae64d82013-08-01 10:50:15 -0700121
122 # Creating Drivers Handles
Jon Hall714eeba2015-09-29 17:53:10 -0700123 initString = "\n" + "*" * 30 + "\n CASE INIT \n" + "*" * 30 + "\n"
124 self.log.exact( initString )
adminbae64d82013-08-01 10:50:15 -0700125 self.driverObject = {}
Jon Hall714eeba2015-09-29 17:53:10 -0700126 self.random_order = 111 # Random order id to connect the components
adminbae64d82013-08-01 10:50:15 -0700127 components_connect_order = {}
Jon Hall714eeba2015-09-29 17:53:10 -0700128 if isinstance( self.componentDictionary, dict ):
adminbae64d82013-08-01 10:50:15 -0700129 for component in self.componentDictionary.keys():
Jon Hall714eeba2015-09-29 17:53:10 -0700130 if 'connect_order' not in self.componentDictionary[component].keys():
131 self.componentDictionary[component]['connect_order'] = str( self.get_random() )
132 components_connect_order[component] = eval( self.componentDictionary[component]['connect_order'] )
133 # Ordering components based on the connect order.
134 ordered_component_list = sorted( components_connect_order,
135 key=lambda key: components_connect_order[key] )
adminbae64d82013-08-01 10:50:15 -0700136 print ordered_component_list
adminbae64d82013-08-01 10:50:15 -0700137 for component in ordered_component_list:
Jon Hall714eeba2015-09-29 17:53:10 -0700138 self.componentInit( component )
adminbae64d82013-08-01 10:50:15 -0700139
Jon Hall714eeba2015-09-29 17:53:10 -0700140 def configparser( self ):
adminbae64d82013-08-01 10:50:15 -0700141 '''
142 It will parse the config file (teston.cfg) and return as dictionary
143 '''
Jon Hall714eeba2015-09-29 17:53:10 -0700144 matchFileName = re.match( r'(.*)\.cfg', self.configFile, re.M | re.I )
adminbae64d82013-08-01 10:50:15 -0700145 if matchFileName:
Jon Hall714eeba2015-09-29 17:53:10 -0700146 xml = open( self.configFile ).read()
147 try:
148 self.configDict = xmldict.xml_to_dict( xml )
adminbae64d82013-08-01 10:50:15 -0700149 return self.configDict
Jon Hall1306a562015-09-04 11:21:24 -0700150 except IOError:
adminbae64d82013-08-01 10:50:15 -0700151 print "There is no such file to parse " + self.configFile
Jon Hall1306a562015-09-04 11:21:24 -0700152 else:
153 print "There is no such file to parse " + self.configFile
kelvin-onlabf70fd542015-05-07 18:41:40 -0700154
Jon Hall714eeba2015-09-29 17:53:10 -0700155 def componentInit( self, component ):
adminbae64d82013-08-01 10:50:15 -0700156 '''
157 This method will initialize specified component
158 '''
159 global driver_options
Jon Hall0fc0d452015-07-14 09:49:58 -0700160 self.initiated = False
Jon Hall714eeba2015-09-29 17:53:10 -0700161 self.log.info( "Creating component Handle: " + component )
Jon Halld61331b2015-02-17 16:35:47 -0800162 driver_options = {}
adminbae64d82013-08-01 10:50:15 -0700163 if 'COMPONENTS' in self.componentDictionary[component].keys():
Jon Hall714eeba2015-09-29 17:53:10 -0700164 driver_options = dict( self.componentDictionary[component]['COMPONENTS'] )
Jon Hall714eeba2015-09-29 17:53:10 -0700165 driver_options['name'] = component
adminbae64d82013-08-01 10:50:15 -0700166 driverName = self.componentDictionary[component]['type']
Jon Hall714eeba2015-09-29 17:53:10 -0700167 driver_options['type'] = driverName
kelvin-onlabf70fd542015-05-07 18:41:40 -0700168
Jon Hall714eeba2015-09-29 17:53:10 -0700169 classPath = self.getDriverPath( driverName.lower() )
170 driverModule = importlib.import_module( classPath )
171 driverClass = getattr( driverModule, driverName )
adminbae64d82013-08-01 10:50:15 -0700172 driverObject = driverClass()
kelvin-onlabf70fd542015-05-07 18:41:40 -0700173
Jon Hall714eeba2015-09-29 17:53:10 -0700174 if "OCN" in self.componentDictionary[component]['host'] and\
175 main.onoscell:
Hari Krishnabe4b97b2015-07-15 12:19:43 -0700176 self.componentDictionary[component]['host'] = main.mnIP
177
Jon Hall714eeba2015-09-29 17:53:10 -0700178 user_name = self.componentDictionary[component].get( 'user',
179 getpass.getuser() )
180 ip_address = self.componentDictionary[component].get( 'host',
181 'localhost' )
182 pwd = self.componentDictionary[component].get( 'password',
183 'changeme' )
184 port = self.componentDictionary[component].get( 'port' )
185 connect_result = driverObject.connect( user_name=user_name,
186 ip_address=ip_address,
187 pwd=pwd,
188 port=port,
189 options=driver_options)
cameron@onlab.us5cc6a372015-05-11 17:18:07 -0700190
adminbae64d82013-08-01 10:50:15 -0700191 if not connect_result:
Jon Hall714eeba2015-09-29 17:53:10 -0700192 self.log.error( "Exiting from the test execution because connecting to the " +
193 component + " component failed." )
Jon Halld61331b2015-02-17 16:35:47 -0800194 self.exit()
kelvin-onlabf70fd542015-05-07 18:41:40 -0700195
Jon Hall714eeba2015-09-29 17:53:10 -0700196 vars( self )[component] = driverObject
Jon Hall0fc0d452015-07-14 09:49:58 -0700197 self.initiated = True
kelvin-onlabf70fd542015-05-07 18:41:40 -0700198
Jon Hall714eeba2015-09-29 17:53:10 -0700199 def run( self ):
adminbae64d82013-08-01 10:50:15 -0700200 '''
Jon Hall714eeba2015-09-29 17:53:10 -0700201 The Execution of the test script's cases listed in the Test params
202 file will be done here then update each test case result.
203 This method will return main.TRUE if it executed all the test cases
204 successfully, else will retun main.FALSE
adminbae64d82013-08-01 10:50:15 -0700205 '''
adminbae64d82013-08-01 10:50:15 -0700206 self.testCaseResult = {}
Jon Halla1185982014-09-15 14:55:10 -0700207 self.TOTAL_TC = 0
adminbae64d82013-08-01 10:50:15 -0700208 self.TOTAL_TC_RUN = 0
Jon Halld61331b2015-02-17 16:35:47 -0800209 self.TOTAL_TC_PLANNED = 0
adminbae64d82013-08-01 10:50:15 -0700210 self.TOTAL_TC_NORESULT = 0
211 self.TOTAL_TC_FAIL = 0
212 self.TOTAL_TC_PASS = 0
Jon Halla1185982014-09-15 14:55:10 -0700213 self.TEST_ITERATION = 0
Jon Hall714eeba2015-09-29 17:53:10 -0700214
215 # NOTE: number of main.step statements in the
216 # outer most level of the test case. used to
217 # execute code in smaller steps
218 self.stepCount = 0
kelvin-onlabf70fd542015-05-07 18:41:40 -0700219 self.CASERESULT = self.NORESULT
220
Jon Halld61331b2015-02-17 16:35:47 -0800221 import testparser
Jon Hall53c5e662016-04-13 16:06:56 -0700222 test = testparser.TestParser( main.testFile )
adminbae64d82013-08-01 10:50:15 -0700223 self.testscript = test.testscript
224 self.code = test.getStepCode()
Jon Hall714eeba2015-09-29 17:53:10 -0700225 repeat = int( self.params.get( 'repeat', 1 ) )
226 self.TOTAL_TC_PLANNED = len( self.testcases_list ) * repeat
kelvin-onlabf70fd542015-05-07 18:41:40 -0700227
adminbae64d82013-08-01 10:50:15 -0700228 result = self.TRUE
Jon Hall714eeba2015-09-29 17:53:10 -0700229 while repeat:
Jon Halla1185982014-09-15 14:55:10 -0700230 for self.CurrentTestCaseNumber in self.testcases_list:
Jon Hall714eeba2015-09-29 17:53:10 -0700231 result = self.runCase( self.CurrentTestCaseNumber )
232 repeat -= 1
adminbae64d82013-08-01 10:50:15 -0700233 return result
kelvin-onlabf70fd542015-05-07 18:41:40 -0700234
Jon Halle234cc42015-08-31 15:26:47 -0700235 def runCase( self, testCaseNumber ):
adminbae64d82013-08-01 10:50:15 -0700236 self.CurrentTestCaseNumber = testCaseNumber
kelvin-onlabf70fd542015-05-07 18:41:40 -0700237 self.CurrentTestCase = ""
Jon Hall714eeba2015-09-29 17:53:10 -0700238
239 # List of step results in a case. ANDed together to get the result
240 self.stepResultsList = []
kelvin-onlabf70fd542015-05-07 18:41:40 -0700241 self.stepName = ""
Jon Hall783bbf92015-07-23 14:33:19 -0700242 self.caseExplanation = ""
adminbae64d82013-08-01 10:50:15 -0700243 result = self.TRUE
Jon Hall714eeba2015-09-29 17:53:10 -0700244
245 # NOTE: number of main.step statements in the
246 # outer most level of the test case. used to
247 # execute code in smaller steps
248 self.stepCount = 0
249
250 # NOTE: This is the current number of main.step()'s executed
251 # in a case. Used for logging.
252 self.stepNumber = 0
adminbae64d82013-08-01 10:50:15 -0700253 self.EXPERIMENTAL_MODE = self.FALSE
254 self.addCaseHeader()
Jon Halle234cc42015-08-31 15:26:47 -0700255 self.testCaseNumber = str( testCaseNumber )
256 self.CASERESULT = self.NORESULT
adminbae64d82013-08-01 10:50:15 -0700257 stopped = False
Jon Hall5a72b712015-09-28 12:20:59 -0700258 try:
259 self.code[self.testCaseNumber]
Jon Halld61331b2015-02-17 16:35:47 -0800260 except KeyError:
Jon Halle234cc42015-08-31 15:26:47 -0700261 self.log.error( "There is no Test-Case " + self.testCaseNumber )
Jon Hallfebb1c72015-03-05 13:30:09 -0800262 return self.FALSE
adminbae64d82013-08-01 10:50:15 -0700263 self.stepCount = 0
Jon Hall714eeba2015-09-29 17:53:10 -0700264 while self.stepCount < len( self.code[self.testCaseNumber].keys() ):
265 result = self.runStep( self.code, self.testCaseNumber )
Jon Hallfebb1c72015-03-05 13:30:09 -0800266 if result == self.FALSE:
adminbae64d82013-08-01 10:50:15 -0700267 break
Jon Hallfebb1c72015-03-05 13:30:09 -0800268 elif result == self.TRUE:
adminbae64d82013-08-01 10:50:15 -0700269 continue
Jon Hall5a72b712015-09-28 12:20:59 -0700270 # stepResults format: ( stepNo[], stepName[], stepResult[], onFail[] )
271 stepResults = self.stepResultsList
Jon Halle234cc42015-08-31 15:26:47 -0700272 if not stopped:
273 if self.CASERESULT == self.TRUE or self.CASERESULT == self.FALSE:
Jon Hall714eeba2015-09-29 17:53:10 -0700274 # Result was already explitily set somewhere else like
275 # in skipCase()
Jon Halle234cc42015-08-31 15:26:47 -0700276 pass
Jon Hall5a72b712015-09-28 12:20:59 -0700277 elif all( self.TRUE == i for i in stepResults ):
kelvin-onlabf70fd542015-05-07 18:41:40 -0700278 # ALL PASSED
279 self.CASERESULT = self.TRUE
Jon Hall5a72b712015-09-28 12:20:59 -0700280 elif self.FALSE in stepResults:
kelvin-onlabf70fd542015-05-07 18:41:40 -0700281 # AT LEAST ONE FAILED
282 self.CASERESULT = self.FALSE
Jon Hall5a72b712015-09-28 12:20:59 -0700283 elif self.TRUE in stepResults:
kelvin-onlabf70fd542015-05-07 18:41:40 -0700284 # AT LEAST ONE PASSED
285 self.CASERESULT = self.TRUE
286 else:
287 self.CASERESULT = self.NORESULT
Jon Hall714eeba2015-09-29 17:53:10 -0700288 self.testCaseResult[str( self.CurrentTestCaseNumber )] = self.CASERESULT
289 self.logger.updateCaseResults( self )
Jon Hall783bbf92015-07-23 14:33:19 -0700290 self.log.wiki( "<p>" + self.caseExplanation + "</p>" )
291 self.log.summary( self.caseExplanation )
kelvin-onlabf70fd542015-05-07 18:41:40 -0700292 self.log.wiki( "<ul>" )
acsmarse2d1ed12015-10-05 13:51:17 -0700293 subcaseMessage = False
kelvin-onlabf70fd542015-05-07 18:41:40 -0700294 for line in self.stepCache.splitlines():
acsmarse2d1ed12015-10-05 13:51:17 -0700295 if re.search( "[0-9]\.[0-9]", line ): # Step
296 if subcaseMessage: # End of Failure Message Printout
297 self.log.wiki( "</ul>\n" )
298 subcaseMessage = False
299 if re.search( " - PASS$", line ):
300 self.log.wiki( "<li>" + line + " <ac:emoticon ac:name=\"tick\" /></li>\n" )
301 elif re.search( " - FAIL$", line ):
302 self.log.wiki( "<li>" + line + " <ac:emoticon ac:name=\"cross\" /></li>\n" )
303 elif re.search( " - No Result$", line ):
304 self.log.wiki( "<li>" + line + " <ac:emoticon ac:name=\"warning\" /></li>\n" )
305 else: # Substep
306 if not subcaseMessage: # Open Failure Message Printout
307 self.log.wiki( "<ul><li>" + line + "</li>\n" )
308 subcaseMessage = True
309 else: # Add to Failure Message Printout
310 self.log.wiki( "<li>" + line + "</li>\n" )
acsmars27e62dd2015-10-06 11:35:47 -0700311 if subcaseMessage: # End of Failure Message Printout for last item
312 self.log.wiki( "</ul>\n" )
kelvin-onlabf70fd542015-05-07 18:41:40 -0700313 self.log.wiki( "</ul>" )
314 self.log.summary( self.stepCache )
315 self.stepCache = ""
adminbae64d82013-08-01 10:50:15 -0700316 return result
kelvin-onlabf70fd542015-05-07 18:41:40 -0700317
Jon Hall714eeba2015-09-29 17:53:10 -0700318 def runStep( self, code, testCaseNumber ):
adminbae64d82013-08-01 10:50:15 -0700319 if not cli.pause:
Jon Hall5a72b712015-09-28 12:20:59 -0700320 try:
321 step = self.stepCount
322 # stepResults format: ( stepNo, stepName, stepResult, onFail )
323 # NOTE: This is needed to catch results of main.step()'s
324 # called inside functions or loops
325 self.stepResults = ( [], [], [], [] )
adminbae64d82013-08-01 10:50:15 -0700326 exec code[testCaseNumber][step] in module.__dict__
327 self.stepCount = self.stepCount + 1
Jon Hall96b816f2015-11-03 12:00:56 -0800328 self.parseStepResults( testCaseNumber )
Jon Halle234cc42015-08-31 15:26:47 -0700329 except StopIteration: # Raised in self.skipCase()
330 self.log.warn( "Skipping the rest of CASE" +
331 str( testCaseNumber ) )
Jon Hall96b816f2015-11-03 12:00:56 -0800332 self.parseStepResults( testCaseNumber )
Jon Hall714eeba2015-09-29 17:53:10 -0700333 self.stepResultsList.append( self.STEPRESULT )
Jon Halle234cc42015-08-31 15:26:47 -0700334 self.stepCache += "\t\t" + self.onFailMsg + "\n"
335 self.stepCount = self.stepCount + 1
336 return self.FALSE
Jon Hallc1606352015-10-06 14:51:36 -0700337 except StandardError as e:
338 try:
339 stepNo = self.stepResults[0][ self.stepNumber - 1 ]
340 except IndexError:
341 stepNo = "<IndexError>"
342 main.log.warn( "Error trying to get step number. " +
343 "It is likely between step " +
Jon Hall6e709752016-02-01 13:38:46 -0800344 str( self.stepNumber ) + " and step " +
Jon Hallc1606352015-10-06 14:51:36 -0700345 str( self.stepNumber + 1 ) )
346 try:
347 stepName = self.stepResults[1][ self.stepNumber - 1 ]
348 except IndexError:
349 stepName = "<IndexError>"
350 self.log.error( "\nException in the following section of" +
351 " code: " + str( testCaseNumber ) + "." +
352 str( stepNo ) + ": " + stepName )
Jeremyd9e4eb12016-04-13 12:09:06 -0700353 self.log.error( str( e.__class__ ) + str( e.message ) )
adminbae64d82013-08-01 10:50:15 -0700354 self.stepCount = self.stepCount + 1
Jon Hall714eeba2015-09-29 17:53:10 -0700355 self.logger.updateCaseResults( self )
356 # WIKI results
kelvin-onlabf70fd542015-05-07 18:41:40 -0700357 self.log.wiki( "<ul>" )
358 for line in self.stepCache.splitlines():
359 if re.search( " - PASS$", line ):
360 self.log.wiki( "<li>" + line + " <ac:emoticon ac:name=\"tick\" /></li>\n" )
361 elif re.search( " - FAIL$", line ):
362 self.log.wiki( "<li>" + line + " <ac:emoticon ac:name=\"cross\" /></li>\n" )
363 elif re.search( " - No Result$", line ):
364 self.log.wiki( "<li>" + line + " <ac:emoticon ac:name=\"warning\" /></li>\n" )
Jon Hall90627612015-06-09 14:57:02 -0700365 else: # Should only be on fail message
366 self.log.wiki( "<ul><li>" + line + "</li></ul>\n" )
kelvin-onlabf70fd542015-05-07 18:41:40 -0700367 self.log.wiki( "</ul>" )
Jon Hall714eeba2015-09-29 17:53:10 -0700368 # summary results
kelvin-onlabf70fd542015-05-07 18:41:40 -0700369 self.log.summary( self.stepCache )
370 self.stepCache = ""
shahshreya957feaa2015-03-23 16:08:29 -0700371 self.cleanup()
Jon Hall00539b12015-04-03 13:55:46 -0700372 self.exit()
Jon Halle234cc42015-08-31 15:26:47 -0700373 return self.TRUE
adminbae64d82013-08-01 10:50:15 -0700374 if cli.stop:
375 cli.stop = False
adminbae64d82013-08-01 10:50:15 -0700376 self.TOTAL_TC_NORESULT = self.TOTAL_TC_NORESULT + 1
Jon Hall714eeba2015-09-29 17:53:10 -0700377 self.testCaseResult[str( self.CurrentTestCaseNumber )] = "Stopped"
378 self.logger.updateCaseResults( self )
adminbae64d82013-08-01 10:50:15 -0700379 result = self.cleanup()
Jon Halle234cc42015-08-31 15:26:47 -0700380 return self.FALSE
381
Jon Hall96b816f2015-11-03 12:00:56 -0800382 def parseStepResults( self, testCaseNumber ):
383 """
384 Parse throught the step results for the wiki
385 """
386 try:
387 # Iterate through each of the steps and print them
388 for index in range( len( self.stepResults[0] ) ):
389 # stepResults = ( stepNo, stepName, stepResult, onFail )
390 stepNo = self.stepResults[0][ index ]
391 stepName = self.stepResults[1][ index ]
392 stepResult = self.stepResults[2][ index ]
393 onFail = self.stepResults[3][ index ]
394 self.stepCache += "\t" + str( testCaseNumber ) + "."
395 self.stepCache += str( stepNo ) + " "
396 self.stepCache += stepName + " - "
397 if stepResult == self.TRUE:
398 self.stepCache += "PASS\n"
399 elif stepResult == self.FALSE:
400 self.stepCache += "FAIL\n"
401 self.stepCache += "\t\t" + onFail + "\n"
402 else:
403 self.stepCache += "No Result\n"
404 self.stepResultsList.append( stepResult )
405 except Exception:
406 self.log.exception( "Error parsing step results" )
407
Jon Halle234cc42015-08-31 15:26:47 -0700408 def skipCase( self, result="DEFAULT", msg=None ):
409 """
410 Will skip the rest of the code in a test case. The case results will be
411 determined as normal based on completed assertions unless the result
412 argument is given.
413
414 Optional Arguments:
415 result: Case insensite string. Can be 'PASS' or 'FAIL' and will set
416 the case result accordingly.
417 msg: Message to be printed when the case is skipped in the reports.
418 """
419 result = result.upper().strip()
420 if result == "PASS":
421 self.CASERESULT = self.TRUE
422 elif result == "FAIL":
423 self.CASERESULT = self.FALSE
424 self.onFailMsg = "Skipping the rest of this case. "
425 if msg:
426 self.onFailMsg += str( msg )
427 raise StopIteration
kelvin-onlabf70fd542015-05-07 18:41:40 -0700428
Jon Hall714eeba2015-09-29 17:53:10 -0700429 def addCaseHeader( self ):
430 caseHeader = "\n" + "*" * 30 + "\n Result summary for Testcase" +\
431 str( self.CurrentTestCaseNumber ) + "\n" + "*" * 30 + "\n"
432 self.log.exact( caseHeader )
433 caseHeader = "\n" + "*" * 40 + "\nStart of Test Case" +\
434 str( self.CurrentTestCaseNumber ) + " : "
adminbae64d82013-08-01 10:50:15 -0700435 for driver in self.componentDictionary.keys():
Jon Hall714eeba2015-09-29 17:53:10 -0700436 vars( self )[driver + 'log'].info( caseHeader )
kelvin-onlabf70fd542015-05-07 18:41:40 -0700437
Jon Hall714eeba2015-09-29 17:53:10 -0700438 def addCaseFooter( self ):
Jon Hall5a72b712015-09-28 12:20:59 -0700439 stepNo = self.stepResults[0][-2]
Jon Hall714eeba2015-09-29 17:53:10 -0700440 if stepNo > 0:
441 previousStep = " " + str( self.CurrentTestCaseNumber ) + "." +\
442 str( stepNo ) + ": " + str( self.stepName )
443 stepHeader = "\n" + "*" * 40 + "\nEnd of Step " + previousStep +\
444 "\n" + "*" * 40 + "\n"
kelvin-onlabf70fd542015-05-07 18:41:40 -0700445
Jon Hall714eeba2015-09-29 17:53:10 -0700446 caseFooter = "\n" + "*" * 40 + "\nEnd of Test case " +\
447 str( self.CurrentTestCaseNumber ) + "\n" + "*" * 40 + "\n"
kelvin-onlabf70fd542015-05-07 18:41:40 -0700448
adminbae64d82013-08-01 10:50:15 -0700449 for driver in self.driversList:
Jon Hall714eeba2015-09-29 17:53:10 -0700450 vars( self )[driver].write( stepHeader + "\n" + caseFooter )
adminbae64d82013-08-01 10:50:15 -0700451
Jon Hall714eeba2015-09-29 17:53:10 -0700452 def cleanup( self ):
adminbae64d82013-08-01 10:50:15 -0700453 '''
Jon Hall5b586732015-06-11 11:39:39 -0700454 Print a summary of the current test's results then attempt to release
455 all the component handles and the close opened file handles.
adminbae64d82013-08-01 10:50:15 -0700456
Jon Hall5b586732015-06-11 11:39:39 -0700457 This function shouldbe threadsafe such that cleanup will only be
458 executed once per test.
459
460 This will return TRUE if all the component handles and log handles
461 closed properly, else return FALSE.
adminbae64d82013-08-01 10:50:15 -0700462 '''
463 result = self.TRUE
Jon Hall5b586732015-06-11 11:39:39 -0700464 lock = self.cleanupLock
465 if lock.acquire( False ):
466 try:
467 if self.cleanupFlag is False: # First thread to run this
468 self.cleanupFlag = True
Jon Hall0fc0d452015-07-14 09:49:58 -0700469 if self.initiated:
Jon Hall714eeba2015-09-29 17:53:10 -0700470 self.logger.testSummary( self )
Jon Hall892818c2015-10-20 17:58:34 -0700471 components = self.componentDictionary
472 for component in sorted( components,
473 key=lambda item: components[item]['connect_order'],
474 reverse=True ):
Jon Hall714eeba2015-09-29 17:53:10 -0700475 try:
476 tempObject = vars( self )[component]
477 print "Disconnecting from " + str( tempObject.name ) +\
478 ": " + str( tempObject.__class__)
Jon Hall5b586732015-06-11 11:39:39 -0700479 tempObject.disconnect()
Jon Hall1306a562015-09-04 11:21:24 -0700480 except KeyboardInterrupt:
481 pass
482 except KeyError:
483 # Component not created yet
484 self.log.warn( "Could not find the component " +
485 str( component ) )
486 except StandardError:
Jon Hall5b586732015-06-11 11:39:39 -0700487 self.log.exception( "Exception while disconnecting from " +
488 str( component ) )
489 result = self.FALSE
490 # Closing all the driver's session files
491 for driver in self.componentDictionary.keys():
492 try:
Jon Hall714eeba2015-09-29 17:53:10 -0700493 vars( self )[driver].close_log_handles()
Jon Hall1306a562015-09-04 11:21:24 -0700494 except KeyboardInterrupt:
495 pass
496 except KeyError:
497 # Component not created yet
498 self.log.warn( "Could not find the component " +
499 str( driver ) + " while trying to" +
500 " close log file" )
501 except StandardError:
Jon Hall5b586732015-06-11 11:39:39 -0700502 self.log.exception( "Exception while closing log files for " +
503 str( driver ) )
504 result = self.FALSE
505 else:
506 pass # Someone else already ran through this function
507 finally:
508 lock.release()
509 else: # Someone already has a lock
510 # NOTE: This could cause problems if we don't release the lock
511 # correctly
512 lock.acquire() # Wait for the other thread to finish
513 # NOTE: If we don't wait, exit could be called while the thread
514 # with the lock is still cleaning up
515 lock.release()
adminbae64d82013-08-01 10:50:15 -0700516 return result
Jon Halld61331b2015-02-17 16:35:47 -0800517
Jon Hall714eeba2015-09-29 17:53:10 -0700518 def pause( self ):
adminbae64d82013-08-01 10:50:15 -0700519 '''
Jon Hall714eeba2015-09-29 17:53:10 -0700520 This function will pause the test's execution, and will continue after
521 user provide 'resume' command.
adminbae64d82013-08-01 10:50:15 -0700522 '''
523 __builtin__.testthread.pause()
kelvin-onlabf70fd542015-05-07 18:41:40 -0700524
Jon Hall714eeba2015-09-29 17:53:10 -0700525 def onfail( self, *components ):
adminbae64d82013-08-01 10:50:15 -0700526 '''
kelvin-onlabf70fd542015-05-07 18:41:40 -0700527 When test step failed, calling all the components onfail.
adminbae64d82013-08-01 10:50:15 -0700528 '''
adminbae64d82013-08-01 10:50:15 -0700529 if not components:
Jon Hall714eeba2015-09-29 17:53:10 -0700530 try:
adminbae64d82013-08-01 10:50:15 -0700531 for component in self.componentDictionary.keys():
Jon Hall714eeba2015-09-29 17:53:10 -0700532 tempObject = vars( self )[component]
adminbae64d82013-08-01 10:50:15 -0700533 result = tempObject.onfail()
Jon Hall1306a562015-09-04 11:21:24 -0700534 except StandardError as e:
Jon Hall714eeba2015-09-29 17:53:10 -0700535 print str( e )
adminbae64d82013-08-01 10:50:15 -0700536 result = self.FALSE
adminbae64d82013-08-01 10:50:15 -0700537 else:
Jon Hall714eeba2015-09-29 17:53:10 -0700538 try:
adminbae64d82013-08-01 10:50:15 -0700539 for component in components:
Jon Hall714eeba2015-09-29 17:53:10 -0700540 tempObject = vars( self )[component]
adminbae64d82013-08-01 10:50:15 -0700541 result = tempObject.onfail()
Jon Hall1306a562015-09-04 11:21:24 -0700542 except StandardError as e:
Jon Hall714eeba2015-09-29 17:53:10 -0700543 print str( e )
adminbae64d82013-08-01 10:50:15 -0700544 result = self.FALSE
kelvin-onlabf70fd542015-05-07 18:41:40 -0700545
Jon Hall714eeba2015-09-29 17:53:10 -0700546 def getDriverPath( self, driverName ):
adminbae64d82013-08-01 10:50:15 -0700547 '''
Jon Hall714eeba2015-09-29 17:53:10 -0700548 Based on the component 'type' specified in the params , this method
549 will find the absolute path, by recursively searching the name of
550 the component.
551
552 NOTE: This function requires the linux 'find' command.
adminbae64d82013-08-01 10:50:15 -0700553 '''
554 import commands
555
Jon Hall714eeba2015-09-29 17:53:10 -0700556 cmd = "find " + drivers_path + " -name " + driverName + ".py"
557 result = commands.getoutput( cmd )
kelvin-onlabf70fd542015-05-07 18:41:40 -0700558
Jon Hall714eeba2015-09-29 17:53:10 -0700559 result_array = str( result ).split( '\n' )
adminbae64d82013-08-01 10:50:15 -0700560 result_count = 0
kelvin-onlabf70fd542015-05-07 18:41:40 -0700561
adminbae64d82013-08-01 10:50:15 -0700562 for drivers_list in result_array:
Jon Hall714eeba2015-09-29 17:53:10 -0700563 result_count = result_count + 1
564 if result_count > 1:
565 print "Found " + driverName + " " + str( result_count ) + " times:"
566 print str( result_array )
adminbae64d82013-08-01 10:50:15 -0700567 self.exit()
kelvin-onlabf70fd542015-05-07 18:41:40 -0700568
Jon Hall714eeba2015-09-29 17:53:10 -0700569 result = re.sub( "(.*)drivers", "", result )
570 result = re.sub( "\/\/", "/", result )
571 result = re.sub( "\.py", "", result )
572 result = re.sub( "\.pyc", "", result )
573 result = re.sub( "\/", ".", result )
574 result = "drivers" + result
adminbae64d82013-08-01 10:50:15 -0700575 return result
adminbae64d82013-08-01 10:50:15 -0700576
Jon Hall714eeba2015-09-29 17:53:10 -0700577 def step( self, stepDesc ):
adminbae64d82013-08-01 10:50:15 -0700578 '''
579 The step information of the test-case will append to the logs.
580 '''
Jon Hall714eeba2015-09-29 17:53:10 -0700581 previousStep = " " + str( self.CurrentTestCaseNumber ) + "." +\
582 str( self.stepNumber ) + ": " + str( self.stepName )
adminbae64d82013-08-01 10:50:15 -0700583 self.stepName = stepDesc
Jon Hall5a72b712015-09-28 12:20:59 -0700584 self.stepNumber += 1
585 self.stepResults[0].append( self.stepNumber )
586 self.stepResults[1].append( stepDesc )
587 self.stepResults[2].append( self.NORESULT )
588 self.stepResults[3].append( "No on fail message given" )
adminbae64d82013-08-01 10:50:15 -0700589
Jon Hall714eeba2015-09-29 17:53:10 -0700590 stepName = " " + str( self.CurrentTestCaseNumber ) + "." +\
591 str( self.stepNumber ) + ": " + str( stepDesc )
adminbae64d82013-08-01 10:50:15 -0700592 self.log.step(stepName)
593 stepHeader = ""
Jon Hall714eeba2015-09-29 17:53:10 -0700594 line = "\n" + "-" * 45 + "\n"
595 if self.stepNumber > 1:
596 stepHeader = line + "End of Step " + previousStep + line
597 stepHeader += line + "Start of Step" + stepName + line
adminbae64d82013-08-01 10:50:15 -0700598 for driver in self.componentDictionary.keys():
Jon Hall714eeba2015-09-29 17:53:10 -0700599 vars( self )[driver + 'log'].info( stepHeader )
kelvin-onlabf70fd542015-05-07 18:41:40 -0700600
Jon Hall714eeba2015-09-29 17:53:10 -0700601 def case( self, testCaseName ):
adminbae64d82013-08-01 10:50:15 -0700602 '''
603 Test's each test-case information will append to the logs.
604 '''
Jon Halld61331b2015-02-17 16:35:47 -0800605 self.CurrentTestCase = testCaseName
Jon Hall714eeba2015-09-29 17:53:10 -0700606 testCaseName = " " + str( testCaseName )
607 self.log.case( testCaseName )
608 caseHeader = testCaseName + "\n" + "*" * 40 + "\n"
adminbae64d82013-08-01 10:50:15 -0700609 for driver in self.componentDictionary.keys():
Jon Hall714eeba2015-09-29 17:53:10 -0700610 vars( self )[driver + 'log'].info( caseHeader )
kelvin-onlabf70fd542015-05-07 18:41:40 -0700611
Jon Hall714eeba2015-09-29 17:53:10 -0700612 def testDesc( self, description ):
adminbae64d82013-08-01 10:50:15 -0700613 '''
614 Test description will append to the logs.
615 '''
Jon Hall714eeba2015-09-29 17:53:10 -0700616 description = "Test Description : " + str( description )
617 self.log.info( description )
kelvin-onlabf70fd542015-05-07 18:41:40 -0700618
Jon Hall714eeba2015-09-29 17:53:10 -0700619 def _getTest( self ):
adminbae64d82013-08-01 10:50:15 -0700620 '''
Jon Hall714eeba2015-09-29 17:53:10 -0700621 This method will parse the test script to find required test
622 information.
adminbae64d82013-08-01 10:50:15 -0700623 '''
Jon Hall53c5e662016-04-13 16:06:56 -0700624 testFileHandler = open( main.testFile, 'r' )
adminbae64d82013-08-01 10:50:15 -0700625 testFileList = testFileHandler.readlines()
626 testFileHandler.close()
adminbae64d82013-08-01 10:50:15 -0700627 counter = 0
Jon Hall714eeba2015-09-29 17:53:10 -0700628 for index in range( len( testFileList ) ):
629 lineMatch = re.match( '\s+def CASE(\d+)(.*):',
630 testFileList[index],
631 0 )
adminbae64d82013-08-01 10:50:15 -0700632 if lineMatch:
Jon Hall714eeba2015-09-29 17:53:10 -0700633 counter = counter + 1
634 self.TC_PLANNED = len( self.testcases_list )
kelvin-onlabf70fd542015-05-07 18:41:40 -0700635
Jon Hall714eeba2015-09-29 17:53:10 -0700636 def response_parser( self, response, return_format ):
adminbae64d82013-08-01 10:50:15 -0700637 ''' It will load the default response parser '''
638 response_dict = {}
Jon Hall714eeba2015-09-29 17:53:10 -0700639 response_dict = self.response_to_dict( response, return_format )
640 return_format_string = self.dict_to_return_format( response,
641 return_format,
642 response_dict )
adminbae64d82013-08-01 10:50:15 -0700643 return return_format_string
kelvin-onlabf70fd542015-05-07 18:41:40 -0700644
Jon Hall714eeba2015-09-29 17:53:10 -0700645 def response_to_dict( self, response, return_format ):
adminbae64d82013-08-01 10:50:15 -0700646 response_dict = {}
Jon Hall714eeba2015-09-29 17:53:10 -0700647 json_match = re.search( '^\s*{', response )
648 xml_match = re.search( '^\s*\<', response )
649 ini_match = re.search( '^\s*\[', response )
650 if json_match:
651 self.log.info( "Response is in 'JSON' format, converting to '" +
652 return_format + "' format" )
Jon Halld61331b2015-02-17 16:35:47 -0800653 # Formatting the json string
Jon Hall714eeba2015-09-29 17:53:10 -0700654 response = re.sub( r"{\s*'?(\w)", r'{"\1', response )
655 response = re.sub( r",\s*'?(\w)", r',"\1', response )
656 response = re.sub( r"(\w)'?\s*:", r'\1":', response )
657 response = re.sub( r":\s*'(\w)'\s*([,}])", r':"\1"\2', response )
658 try:
adminbae64d82013-08-01 10:50:15 -0700659 import json
Jon Hall714eeba2015-09-29 17:53:10 -0700660 response_dict = json.loads( response )
Jon Hall1306a562015-09-04 11:21:24 -0700661 except StandardError:
Jon Hall2a5002c2015-08-21 16:49:11 -0700662 self.log.exception( "Json Parser is unable to parse the string" )
adminbae64d82013-08-01 10:50:15 -0700663 return response_dict
Jon Hall714eeba2015-09-29 17:53:10 -0700664 elif ini_match:
665 self.log.info( "Response is in 'INI' format, converting to '" +
666 return_format + "' format" )
adminbae64d82013-08-01 10:50:15 -0700667 from configobj import ConfigObj
Jon Hall714eeba2015-09-29 17:53:10 -0700668 response_file = open( "respnse_file.temp", 'w' )
669 response_file.write( response )
Jon Halld61331b2015-02-17 16:35:47 -0800670 response_file.close()
Jon Hall714eeba2015-09-29 17:53:10 -0700671 response_dict = ConfigObj( "respnse_file.temp" )
adminbae64d82013-08-01 10:50:15 -0700672 return response_dict
Jon Hall714eeba2015-09-29 17:53:10 -0700673 elif xml_match:
674 self.log.info( "Response is in 'XML' format, converting to '" +
675 return_format + "' format" )
676 try:
677 response_dict = xmldict.xml_to_dict( "<response> " +
678 str( response ) +
679 " </response>" )
Jon Hall1306a562015-09-04 11:21:24 -0700680 except StandardError:
681 self.log.exception()
adminbae64d82013-08-01 10:50:15 -0700682 return response_dict
kelvin-onlabf70fd542015-05-07 18:41:40 -0700683
Jon Hall714eeba2015-09-29 17:53:10 -0700684 def dict_to_return_format( self, response, return_format, response_dict ):
685 if return_format == 'table':
adminbae64d82013-08-01 10:50:15 -0700686 ''' Will return in table format'''
687 to_do = "Call the table output formatter"
688 global response_table
689 response_table = '\n'
Jon Hall714eeba2015-09-29 17:53:10 -0700690 response_table = response_table + '\t'.join( response_dict ) + "\n"
kelvin-onlabf70fd542015-05-07 18:41:40 -0700691
Jon Hall714eeba2015-09-29 17:53:10 -0700692 def get_table( value_to_convert ):
693 ''' This will parse the dictionary recusrsively and print as
694 table format'''
adminbae64d82013-08-01 10:50:15 -0700695 table_data = ""
Jon Hall714eeba2015-09-29 17:53:10 -0700696 if isinstance( value_to_convert, dict ):
697 table_data = table_data + '\t'.join( value_to_convert ) +\
698 "\n"
699 for temp_val in value_to_convert.values():
700 table_data = table_data + get_table( temp_val )
701 else:
702 table_data = table_data + str( value_to_convert ) + "\t"
Jon Halld61331b2015-02-17 16:35:47 -0800703 return table_data
kelvin-onlabf70fd542015-05-07 18:41:40 -0700704
Jon Hall714eeba2015-09-29 17:53:10 -0700705 for value in response_dict.values():
706 response_table = response_table + get_table( value )
adminbae64d82013-08-01 10:50:15 -0700707 return response_table
kelvin-onlabf70fd542015-05-07 18:41:40 -0700708
Jon Hall714eeba2015-09-29 17:53:10 -0700709 elif return_format == 'config':
adminbae64d82013-08-01 10:50:15 -0700710 ''' Will return in config format'''
711 to_do = 'Call dict to config coverter'
Jon Hall714eeba2015-09-29 17:53:10 -0700712 response_string = str( response_dict )
adminbae64d82013-08-01 10:50:15 -0700713 print response_string
Jon Hall714eeba2015-09-29 17:53:10 -0700714 response_config = re.sub( ",", "\n\t", response_string )
715 response_config = re.sub( "u\'", "\'", response_config )
716 response_config = re.sub( "{", "", response_config )
717 response_config = re.sub( "}", "\n", response_config )
718 response_config = re.sub( ":", " =", response_config )
719 return "[response]\n\t " + response_config
adminbae64d82013-08-01 10:50:15 -0700720 elif return_format == 'xml':
721 ''' Will return in xml format'''
Jon Hall714eeba2015-09-29 17:53:10 -0700722 response_xml = xmldict.dict_to_xml( response_dict )
723 response_xml = re.sub( ">\s*<", ">\n<", response_xml )
724 return "\n" + response_xml
adminbae64d82013-08-01 10:50:15 -0700725 elif return_format == 'json':
726 ''' Will return in json format'''
727 to_do = 'Call dict to xml coverter'
728 import json
Jon Hall714eeba2015-09-29 17:53:10 -0700729 response_json = json.dumps( response_dict )
adminbae64d82013-08-01 10:50:15 -0700730 return response_json
kelvin-onlabf70fd542015-05-07 18:41:40 -0700731
Jon Hall714eeba2015-09-29 17:53:10 -0700732 def get_random( self ):
adminbae64d82013-08-01 10:50:15 -0700733 self.random_order = self.random_order + 1
734 return self.random_order
kelvin-onlabf70fd542015-05-07 18:41:40 -0700735
Jon Hall714eeba2015-09-29 17:53:10 -0700736 def exit( self ):
adminbae64d82013-08-01 10:50:15 -0700737 __builtin__.testthread = None
Jon Hall5b586732015-06-11 11:39:39 -0700738 for thread in threading.enumerate():
739 if thread.isAlive():
740 try:
741 thread._Thread__stop()
742 except:
Jon Hall1306a562015-09-04 11:21:24 -0700743 # NOTE: We should catch any exceptions while trying to
744 # close the thread so that we can try to close the other
745 # threads as well
Jon Hall714eeba2015-09-29 17:53:10 -0700746 print str( thread.getName() ) +\
747 ' could not be terminated'
adminbae64d82013-08-01 10:50:15 -0700748 sys.exit()
749
Jon Hallcd3d2a32015-10-01 11:07:28 -0700750 def stop( self, email=False ):
751 """
752 Stop the test until Ctrl-D is entered.
753 Ctrl-C will kill the test
Jon Hall25079782015-10-13 13:54:39 -0700754
755 Optional arguments:
756 email can either be a bool, or you can specify the email address
757 to send the email to
Jon Hallcd3d2a32015-10-01 11:07:28 -0700758 """
759 try:
760 if email:
Jon Hall25079782015-10-13 13:54:39 -0700761 if '@' in email:
762 main.mail = email
763 utilities.send_warning_email()
Jon Hallcd3d2a32015-10-01 11:07:28 -0700764 self.log.error( "Test execution suspended. Press Ctrl-D to "
765 "resume or Ctrl-C to exit the test" )
766 # NOTE: Ctrl-D needs to be entered on a new line
767 while True:
768 # TODO: we could give the user an interactive prompt where
769 # they could call functions
770 raw_input()
771 except EOFError:
772 return
773 # Pass all other exceptions up to caller
774
775
Jon Hall714eeba2015-09-29 17:53:10 -0700776def verifyOptions( options ):
adminbae64d82013-08-01 10:50:15 -0700777 '''
Jon Hall714eeba2015-09-29 17:53:10 -0700778 This will verify the command line options and set to default values,
779 if any option not given in command line.
adminbae64d82013-08-01 10:50:15 -0700780 '''
Jon Hall714eeba2015-09-29 17:53:10 -0700781 verifyTest( options )
782 verifyExample( options )
783 verifyTestScript( options )
YPZhang1c89e762016-06-29 10:43:58 -0700784 verifyParams( options )
Jon Hall714eeba2015-09-29 17:53:10 -0700785 verifyLogdir( options )
786 verifyMail( options )
787 verifyTestCases( options )
788 verifyOnosCell( options )
adminbae64d82013-08-01 10:50:15 -0700789
Jon Hall714eeba2015-09-29 17:53:10 -0700790def verifyTest( options ):
Jon Hall44506242015-07-29 17:40:26 -0700791 try:
792 if options.testname:
793 main.TEST = options.testname
Jon Hall714eeba2015-09-29 17:53:10 -0700794 main.classPath = "tests." + main.TEST + "." + main.TEST
Jon Hall44506242015-07-29 17:40:26 -0700795 main.tests_path = tests_path
796 elif options.example:
797 main.TEST = options.example
Jon Hall714eeba2015-09-29 17:53:10 -0700798 main.tests_path = path + "/examples/"
799 main.classPath = "examples." + main.TEST + "." + main.TEST
Jon Hall44506242015-07-29 17:40:26 -0700800 except AttributeError:
adminbae64d82013-08-01 10:50:15 -0700801 print "Test or Example not specified please specify the --test <test name > or --example <example name>"
Jon Hall5b586732015-06-11 11:39:39 -0700802 main.exit()
adminbae64d82013-08-01 10:50:15 -0700803
Jon Hall714eeba2015-09-29 17:53:10 -0700804def verifyExample( options ):
adminbae64d82013-08-01 10:50:15 -0700805 if options.example:
Jon Hall714eeba2015-09-29 17:53:10 -0700806 main.testDir = path + '/examples/'
807 main.tests_path = path + "/examples/"
808 main.classPath = "examples." + main.TEST + "." + main.TEST
kelvin-onlabf70fd542015-05-07 18:41:40 -0700809
Jon Hall714eeba2015-09-29 17:53:10 -0700810def verifyLogdir( options ):
Jon Hall88e498c2015-03-06 09:54:35 -0800811 # Verifying Log directory option
adminbae64d82013-08-01 10:50:15 -0700812 if options.logdir:
813 main.logdir = options.logdir
Jon Hall714eeba2015-09-29 17:53:10 -0700814 else:
Jon Halld61331b2015-02-17 16:35:47 -0800815 main.logdir = main.FALSE
kelvin-onlabf70fd542015-05-07 18:41:40 -0700816
Jon Hall714eeba2015-09-29 17:53:10 -0700817def verifyMail( options ):
Jon Hall25079782015-10-13 13:54:39 -0700818 # Mail-To: field
819 if options.mail: # Test run specific
adminbae64d82013-08-01 10:50:15 -0700820 main.mail = options.mail
Jon Hall25079782015-10-13 13:54:39 -0700821 elif main.params.get('mail'): # Test suite specific
822 main.mail = main.params.get( 'mail' )
823 else: # TestON specific
824 main.mail = main.config['config'].get( 'mail_to' )
825 # Mail-From: field
826 main.sender = main.config['config'].get( 'mail_from' )
827 # Mail smtp server
828 main.smtp = main.config['config'].get( 'mail_server' )
829 # Mail-From account password
830 main.senderPwd = main.config['config'].get( 'mail_pass' )
831
adminbae64d82013-08-01 10:50:15 -0700832
Jon Hall714eeba2015-09-29 17:53:10 -0700833def verifyTestCases( options ):
Jon Hall88e498c2015-03-06 09:54:35 -0800834 # Getting Test cases list
adminbae64d82013-08-01 10:50:15 -0700835 if options.testcases:
Jon Hallfebb1c72015-03-05 13:30:09 -0800836 testcases_list = options.testcases
Jon Hall88e498c2015-03-06 09:54:35 -0800837 # sys.exit()
Jon Hall714eeba2015-09-29 17:53:10 -0700838 testcases_list = re.sub( "(\[|\])", "", options.testcases )
839 main.testcases_list = eval( testcases_list + "," )
840 else:
adminbae64d82013-08-01 10:50:15 -0700841 if 'testcases' in main.params.keys():
Jon Hall714eeba2015-09-29 17:53:10 -0700842 temp = eval( main.params['testcases'] + "," )
843 list1 = []
844 if isinstance( temp[0], list ):
Jon Hallfebb1c72015-03-05 13:30:09 -0800845 for test in temp:
846 for testcase in test:
Jon Hall714eeba2015-09-29 17:53:10 -0700847 if isinstance( testcase, int ):
848 testcase = [testcase]
849 list1.extend( testcase )
850 else:
851 temp = list( temp )
Jon Hallfebb1c72015-03-05 13:30:09 -0800852 for testcase in temp:
Jon Hall714eeba2015-09-29 17:53:10 -0700853 if isinstance( testcase, int ):
854 testcase = [testcase]
855 list1.extend( testcase )
856 main.testcases_list = list1
857 else:
858 print "Testcases not specifed in params, please provide in " +\
859 "params file or 'testcases' commandline argument"
Jon Halld61331b2015-02-17 16:35:47 -0800860 sys.exit()
kelvin-onlabf70fd542015-05-07 18:41:40 -0700861
Jon Hall714eeba2015-09-29 17:53:10 -0700862def verifyOnosCell( options ):
Hari Krishnabe4b97b2015-07-15 12:19:43 -0700863 # Verifying onoscell option
Hari Krishna03f530e2015-07-10 17:28:27 -0700864 if options.onoscell:
865 main.onoscell = options.onoscell
Hari Krishnabe4b97b2015-07-15 12:19:43 -0700866 main.onosIPs = []
867 main.mnIP = ""
Jon Hall714eeba2015-09-29 17:53:10 -0700868 cellCMD = ". ~/.profile; cell " + main.onoscell
869 output = subprocess.check_output( ["bash", '-c', cellCMD] )
Hari Krishnabe4b97b2015-07-15 12:19:43 -0700870 splitOutput = output.splitlines()
Jon Hall714eeba2015-09-29 17:53:10 -0700871 for i in range( len( splitOutput ) ):
872 if re.match( "OCN", splitOutput[i] ):
873 mnNode = splitOutput[i].split( "=" )
Hari Krishnabe4b97b2015-07-15 12:19:43 -0700874 main.mnIP = mnNode[1]
Jon Hall714eeba2015-09-29 17:53:10 -0700875 # cell already sorts OC variables in bash, so no need to
876 # sort in TestON
877 if re.match( "OC[1-9]", splitOutput[i] ):
878 onosNodes = splitOutput[i].split( "=" )
Hari Krishnabe4b97b2015-07-15 12:19:43 -0700879 main.onosIPs.append( onosNodes[1] )
Jon Hall714eeba2015-09-29 17:53:10 -0700880 else:
Hari Krishna03f530e2015-07-10 17:28:27 -0700881 main.onoscell = main.FALSE
882
Jon Hall714eeba2015-09-29 17:53:10 -0700883def verifyTestScript( options ):
adminbae64d82013-08-01 10:50:15 -0700884 '''
885 Verifyies test script.
886 '''
Jon Halld61331b2015-02-17 16:35:47 -0800887 main.openspeak = openspeak.OpenSpeak()
Jon Hall53c5e662016-04-13 16:06:56 -0700888 directory = main.testDir + "/" + main.TEST
889 if os.path.exists( directory ):
890 pass
891 else:
892 directory = ""
893 for root, dirs, files in os.walk( main.testDir, topdown=True):
894 if not directory:
895 for name in dirs:
896 if name == main.TEST:
897 directory = ( os.path.join( root, name ) )
898 index = directory.find( "/tests/" ) + 1
899 main.classPath = directory[index:].replace( '/', '.' ) + "." + main.TEST
900 break
901 openspeakfile = directory + "/" + main.TEST + ".ospk"
902 main.testFile = directory + "/" + main.TEST + ".py"
Jon Hall714eeba2015-09-29 17:53:10 -0700903 if os.path.exists( openspeakfile ):
Jon Hall44506242015-07-29 17:40:26 -0700904 # Openspeak file found, compiling to python
Jon Hall714eeba2015-09-29 17:53:10 -0700905 main.openspeak.compiler( openspeakfile=openspeakfile, writetofile=1 )
Jon Hall53c5e662016-04-13 16:06:56 -0700906 elif os.path.exists( main.testFile ):
Jon Hall44506242015-07-29 17:40:26 -0700907 # No openspeak found, using python file instead
908 pass
adminbae64d82013-08-01 10:50:15 -0700909 else:
Jon Hall714eeba2015-09-29 17:53:10 -0700910 print "\nThere is no \"" + main.TEST + "\" test script.\nPlease provide a " +\
Jon Hall44506242015-07-29 17:40:26 -0700911 "Python or OpenSpeak test script in the tests folder: " +\
Jon Hall714eeba2015-09-29 17:53:10 -0700912 main.testDir + "/" + main.TEST + "/"
adminbae64d82013-08-01 10:50:15 -0700913 __builtin__.testthread = None
914 main.exit()
Jon Hall714eeba2015-09-29 17:53:10 -0700915 try:
916 testModule = __import__( main.classPath,
917 globals(),
918 locals(),
919 [main.TEST],
920 -1 )
Jon Hall1306a562015-09-04 11:21:24 -0700921 except ImportError:
Jon Hall714eeba2015-09-29 17:53:10 -0700922 print "There was an import error, it might mean that there is " +\
923 "no test named " + main.TEST
Jon Halld61331b2015-02-17 16:35:47 -0800924 main.exit()
adminbae64d82013-08-01 10:50:15 -0700925
Jon Hall714eeba2015-09-29 17:53:10 -0700926 testClass = getattr( testModule, main.TEST )
adminbae64d82013-08-01 10:50:15 -0700927 main.testObject = testClass()
928 load_parser()
Jon Hall714eeba2015-09-29 17:53:10 -0700929 main.params = main.parser.parseParams( main.classPath )
930 main.topology = main.parser.parseTopology( main.classPath )
kelvin-onlabf70fd542015-05-07 18:41:40 -0700931
YPZhang1c89e762016-06-29 10:43:58 -0700932def verifyParams( options ):
Jon Hall714eeba2015-09-29 17:53:10 -0700933 try:
adminbae64d82013-08-01 10:50:15 -0700934 main.params = main.params['PARAMS']
Jon Hall1306a562015-09-04 11:21:24 -0700935 except KeyError:
Jon Hall714eeba2015-09-29 17:53:10 -0700936 print "Error with the params file: Either the file not specified " +\
937 "or the format is not correct"
Jon Halld61331b2015-02-17 16:35:47 -0800938 main.exit()
Jon Hall714eeba2015-09-29 17:53:10 -0700939 try:
adminbae64d82013-08-01 10:50:15 -0700940 main.topology = main.topology['TOPOLOGY']
Jon Hall1306a562015-09-04 11:21:24 -0700941 except KeyError:
Jon Hall714eeba2015-09-29 17:53:10 -0700942 print "Error with the Topology file: Either the file not specified " +\
943 "or the format is not correct"
adminbae64d82013-08-01 10:50:15 -0700944 main.exit()
YPZhang1c89e762016-06-29 10:43:58 -0700945 # Overwrite existing params variables if they are specified from command line
946 if len(options.params) > 0:
947 # Some params variables are specified from command line
948 for param in options.params:
949 if not re.search( ".=.", param ):
950 print( "Error when parsing params: params should follow key=value format" )
951 continue
952 # Split the param string to netest keys and value
953 [ keys, value ] = param.split( "=" )
954 # Split the nested keys according to its hierarchy
955 keyList = keys.split( "/" )
956 # Get the outermost dictionary
957 paramDict = main.params
958 # Get the innermost dictionary
959 try:
960 while len( keyList ) > 1:
961 key = keyList.pop(0)
962 assert isinstance( paramDict[ key ], dict )
963 paramDict = paramDict[ key ]
964 except KeyError:
965 print( "Error when parsing params: key \"" + key + "\" not found in main.params" )
966 main.exit()
967 except AssertionError:
968 print( "Error when parsing params: \"" + key + "\" is already the innermost level in main.params" )
969 main.exit()
970 # Change the value
971 if not paramDict.has_key( keyList[0] ):
972 print( "Error when parsing params: key \"" + keyList[0] + "\" not found in main.params" )
973 main.exit()
974 elif isinstance( paramDict[ keyList[0] ], dict ):
975 print( "Error when parsing params: more levels under key \"" + keyList[0] + "\" in main.params" )
976 main.exit()
977 else:
978 paramDict[ keyList[0] ] = value
kelvin-onlabf70fd542015-05-07 18:41:40 -0700979
Jon Hall714eeba2015-09-29 17:53:10 -0700980def load_parser():
adminbae64d82013-08-01 10:50:15 -0700981 '''
982 It facilitates the loading customised parser for topology and params file.
983 It loads parser mentioned in tab named parser of teston.cfg file.
Jon Hall714eeba2015-09-29 17:53:10 -0700984 It also loads default xmlparser if no parser have specified in teston.cfg
985 file.
adminbae64d82013-08-01 10:50:15 -0700986
987 '''
988 confighash = main.configDict
Jon Hall714eeba2015-09-29 17:53:10 -0700989 if 'file' in confighash['config']['parser'] and\
990 'class' in confighash['config']['parser']:
Jon Hall44506242015-07-29 17:40:26 -0700991 path = confighash['config']['parser']['file']
Jon Hall714eeba2015-09-29 17:53:10 -0700992 if path is not None or\
993 confighash['config']['parser']['class'] is not None:
Jon Hall44506242015-07-29 17:40:26 -0700994 try:
995 module = re.sub( r".py\s*$", "", path )
adminbae64d82013-08-01 10:50:15 -0700996 moduleList = module.split("/")
Jon Hall714eeba2015-09-29 17:53:10 -0700997 newModule = ".".join( moduleList[-2:] )
Jon Hall44506242015-07-29 17:40:26 -0700998 parsingClass = confighash['config']['parser']['class']
Jon Hall714eeba2015-09-29 17:53:10 -0700999 parsingModule = __import__( newModule,
1000 globals(),
1001 locals(),
1002 [parsingClass],
1003 -1 )
1004 parsingClass = getattr( parsingModule, parsingClass )
Jon Hall44506242015-07-29 17:40:26 -07001005 main.parser = parsingClass()
Jon Hall714eeba2015-09-29 17:53:10 -07001006 if hasattr( main.parser, "parseParams" ) and\
1007 hasattr( main.parser, "parseTopology" ) and\
1008 hasattr( main.parser, "parse" ):
Jon Hall44506242015-07-29 17:40:26 -07001009 pass
1010 else:
1011 print "Invalid parser format"
adminbae64d82013-08-01 10:50:15 -07001012 main.exit()
Jon Hall44506242015-07-29 17:40:26 -07001013 except ImportError:
Jon Hall714eeba2015-09-29 17:53:10 -07001014 print "Could not find the file " + path +\
1015 " using default parser."
Jon Halld61331b2015-02-17 16:35:47 -08001016 load_defaultParser()
Jon Hall714eeba2015-09-29 17:53:10 -07001017 elif confighash['config']['parser']['file'] is None or\
1018 confighash['config']['parser']['class'] is None:
Jon Halld61331b2015-02-17 16:35:47 -08001019 load_defaultParser()
adminbae64d82013-08-01 10:50:15 -07001020 else:
1021 load_defaultParser()
1022
1023def load_defaultParser():
1024 '''
Jon Hall714eeba2015-09-29 17:53:10 -07001025 It will load the default parser which is xml parser to parse the params and
1026 topology file.
adminbae64d82013-08-01 10:50:15 -07001027 '''
1028 moduleList = main.parserPath.split("/")
Jon Hall714eeba2015-09-29 17:53:10 -07001029 newModule = ".".join( moduleList[-2:] )
1030 try:
Jon Halld61331b2015-02-17 16:35:47 -08001031 parsingClass = main.parsingClass
Jon Hall714eeba2015-09-29 17:53:10 -07001032 parsingModule = __import__( newModule,
1033 globals(),
1034 locals(),
1035 [parsingClass],
1036 -1 )
1037 parsingClass = getattr( parsingModule, parsingClass )
adminbae64d82013-08-01 10:50:15 -07001038 main.parser = parsingClass()
Jon Hall714eeba2015-09-29 17:53:10 -07001039 if hasattr( main.parser, "parseParams" ) and\
1040 hasattr( main.parser, "parseTopology" ) and\
1041 hasattr( main.parser, "parse" ):
adminbae64d82013-08-01 10:50:15 -07001042 pass
1043 else:
1044 main.exit()
adminbae64d82013-08-01 10:50:15 -07001045 except ImportError:
1046 print sys.exc_info()[1]
1047
Jon Hall714eeba2015-09-29 17:53:10 -07001048def load_logger():
adminbae64d82013-08-01 10:50:15 -07001049 '''
1050 It facilitates the loading customised parser for topology and params file.
1051 It loads parser mentioned in tab named parser of teston.cfg file.
Jon Hall714eeba2015-09-29 17:53:10 -07001052 It also loads default xmlparser if no parser have specified in teston.cfg
1053 file.
adminbae64d82013-08-01 10:50:15 -07001054 '''
1055 confighash = main.configDict
Jon Hall714eeba2015-09-29 17:53:10 -07001056 if 'file' in confighash['config']['logger'] and\
1057 'class' in confighash['config']['logger']:
Jon Hall44506242015-07-29 17:40:26 -07001058 path = confighash['config']['logger']['file']
Jon Hall714eeba2015-09-29 17:53:10 -07001059 if path is not None or\
1060 confighash['config']['logger']['class'] is not None:
Jon Hall44506242015-07-29 17:40:26 -07001061 try:
1062 module = re.sub( r".py\s*$", "", path )
Jon Hall714eeba2015-09-29 17:53:10 -07001063 moduleList = module.split( "/" )
1064 newModule = ".".join( moduleList[-2:] )
Jon Hall44506242015-07-29 17:40:26 -07001065 loggerClass = confighash['config']['logger']['class']
Jon Hall714eeba2015-09-29 17:53:10 -07001066 loggerModule = __import__( newModule,
1067 globals(),
1068 locals(),
1069 [loggerClass],
1070 -1 )
1071 loggerClass = getattr( loggerModule, loggerClass )
Jon Hall44506242015-07-29 17:40:26 -07001072 main.logger = loggerClass()
Jon Hall44506242015-07-29 17:40:26 -07001073 except ImportError:
Jon Hall714eeba2015-09-29 17:53:10 -07001074 print "Could not find the file " + path +\
1075 " using default logger."
adminbae64d82013-08-01 10:50:15 -07001076 load_defaultlogger()
Jon Hall714eeba2015-09-29 17:53:10 -07001077 elif confighash['config']['parser']['file'] is None or\
1078 confighash['config']['parser']['class'] is None:
Jon Halld61331b2015-02-17 16:35:47 -08001079 load_defaultlogger()
adminbae64d82013-08-01 10:50:15 -07001080 else:
1081 load_defaultlogger()
1082
1083def load_defaultlogger():
1084 '''
Jon Hall714eeba2015-09-29 17:53:10 -07001085 It will load the default parser which is xml parser to parse the params and
1086 topology file.
adminbae64d82013-08-01 10:50:15 -07001087 '''
1088 moduleList = main.loggerPath.split("/")
Jon Hall714eeba2015-09-29 17:53:10 -07001089 newModule = ".".join( moduleList[-2:] )
1090 try:
Jon Halld61331b2015-02-17 16:35:47 -08001091 loggerClass = main.loggerClass
Jon Hall714eeba2015-09-29 17:53:10 -07001092 loggerModule = __import__( newModule,
1093 globals(),
1094 locals(),
1095 [loggerClass],
1096 -1 )
1097 loggerClass = getattr( loggerModule, loggerClass )
adminbae64d82013-08-01 10:50:15 -07001098 main.logger = loggerClass()
1099
1100 except ImportError:
1101 print sys.exc_info()[1]
Jon Halld61331b2015-02-17 16:35:47 -08001102 main.exit()
adminbae64d82013-08-01 10:50:15 -07001103
Jon Hall714eeba2015-09-29 17:53:10 -07001104def _echo( self ):
adminbae64d82013-08-01 10:50:15 -07001105 print "THIS IS ECHO"