blob: 76f7842ca2c6a455259a2a1dc72832d7e286219d [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 Hall714eeba2015-09-29 17:53:10 -0700222 testFile = self.tests_path + "/" + self.TEST + "/" + self.TEST + ".py"
223 test = testparser.TestParser( testFile )
adminbae64d82013-08-01 10:50:15 -0700224 self.testscript = test.testscript
225 self.code = test.getStepCode()
Jon Hall714eeba2015-09-29 17:53:10 -0700226 repeat = int( self.params.get( 'repeat', 1 ) )
227 self.TOTAL_TC_PLANNED = len( self.testcases_list ) * repeat
kelvin-onlabf70fd542015-05-07 18:41:40 -0700228
adminbae64d82013-08-01 10:50:15 -0700229 result = self.TRUE
Jon Hall714eeba2015-09-29 17:53:10 -0700230 while repeat:
Jon Halla1185982014-09-15 14:55:10 -0700231 for self.CurrentTestCaseNumber in self.testcases_list:
Jon Hall714eeba2015-09-29 17:53:10 -0700232 result = self.runCase( self.CurrentTestCaseNumber )
233 repeat -= 1
adminbae64d82013-08-01 10:50:15 -0700234 return result
kelvin-onlabf70fd542015-05-07 18:41:40 -0700235
Jon Halle234cc42015-08-31 15:26:47 -0700236 def runCase( self, testCaseNumber ):
adminbae64d82013-08-01 10:50:15 -0700237 self.CurrentTestCaseNumber = testCaseNumber
kelvin-onlabf70fd542015-05-07 18:41:40 -0700238 self.CurrentTestCase = ""
Jon Hall714eeba2015-09-29 17:53:10 -0700239
240 # List of step results in a case. ANDed together to get the result
241 self.stepResultsList = []
kelvin-onlabf70fd542015-05-07 18:41:40 -0700242 self.stepName = ""
Jon Hall783bbf92015-07-23 14:33:19 -0700243 self.caseExplanation = ""
adminbae64d82013-08-01 10:50:15 -0700244 result = self.TRUE
Jon Hall714eeba2015-09-29 17:53:10 -0700245
246 # NOTE: number of main.step statements in the
247 # outer most level of the test case. used to
248 # execute code in smaller steps
249 self.stepCount = 0
250
251 # NOTE: This is the current number of main.step()'s executed
252 # in a case. Used for logging.
253 self.stepNumber = 0
adminbae64d82013-08-01 10:50:15 -0700254 self.EXPERIMENTAL_MODE = self.FALSE
255 self.addCaseHeader()
Jon Halle234cc42015-08-31 15:26:47 -0700256 self.testCaseNumber = str( testCaseNumber )
257 self.CASERESULT = self.NORESULT
adminbae64d82013-08-01 10:50:15 -0700258 stopped = False
Jon Hall5a72b712015-09-28 12:20:59 -0700259 try:
260 self.code[self.testCaseNumber]
Jon Halld61331b2015-02-17 16:35:47 -0800261 except KeyError:
Jon Halle234cc42015-08-31 15:26:47 -0700262 self.log.error( "There is no Test-Case " + self.testCaseNumber )
Jon Hallfebb1c72015-03-05 13:30:09 -0800263 return self.FALSE
adminbae64d82013-08-01 10:50:15 -0700264 self.stepCount = 0
Jon Hall714eeba2015-09-29 17:53:10 -0700265 while self.stepCount < len( self.code[self.testCaseNumber].keys() ):
266 result = self.runStep( self.code, self.testCaseNumber )
Jon Hallfebb1c72015-03-05 13:30:09 -0800267 if result == self.FALSE:
adminbae64d82013-08-01 10:50:15 -0700268 break
Jon Hallfebb1c72015-03-05 13:30:09 -0800269 elif result == self.TRUE:
adminbae64d82013-08-01 10:50:15 -0700270 continue
Jon Hall5a72b712015-09-28 12:20:59 -0700271 # stepResults format: ( stepNo[], stepName[], stepResult[], onFail[] )
272 stepResults = self.stepResultsList
Jon Halle234cc42015-08-31 15:26:47 -0700273 if not stopped:
274 if self.CASERESULT == self.TRUE or self.CASERESULT == self.FALSE:
Jon Hall714eeba2015-09-29 17:53:10 -0700275 # Result was already explitily set somewhere else like
276 # in skipCase()
Jon Halle234cc42015-08-31 15:26:47 -0700277 pass
Jon Hall5a72b712015-09-28 12:20:59 -0700278 elif all( self.TRUE == i for i in stepResults ):
kelvin-onlabf70fd542015-05-07 18:41:40 -0700279 # ALL PASSED
280 self.CASERESULT = self.TRUE
Jon Hall5a72b712015-09-28 12:20:59 -0700281 elif self.FALSE in stepResults:
kelvin-onlabf70fd542015-05-07 18:41:40 -0700282 # AT LEAST ONE FAILED
283 self.CASERESULT = self.FALSE
Jon Hall5a72b712015-09-28 12:20:59 -0700284 elif self.TRUE in stepResults:
kelvin-onlabf70fd542015-05-07 18:41:40 -0700285 # AT LEAST ONE PASSED
286 self.CASERESULT = self.TRUE
287 else:
288 self.CASERESULT = self.NORESULT
Jon Hall714eeba2015-09-29 17:53:10 -0700289 self.testCaseResult[str( self.CurrentTestCaseNumber )] = self.CASERESULT
290 self.logger.updateCaseResults( self )
Jon Hall783bbf92015-07-23 14:33:19 -0700291 self.log.wiki( "<p>" + self.caseExplanation + "</p>" )
292 self.log.summary( self.caseExplanation )
kelvin-onlabf70fd542015-05-07 18:41:40 -0700293 self.log.wiki( "<ul>" )
acsmarse2d1ed12015-10-05 13:51:17 -0700294 subcaseMessage = False
kelvin-onlabf70fd542015-05-07 18:41:40 -0700295 for line in self.stepCache.splitlines():
acsmarse2d1ed12015-10-05 13:51:17 -0700296 if re.search( "[0-9]\.[0-9]", line ): # Step
297 if subcaseMessage: # End of Failure Message Printout
298 self.log.wiki( "</ul>\n" )
299 subcaseMessage = False
300 if re.search( " - PASS$", line ):
301 self.log.wiki( "<li>" + line + " <ac:emoticon ac:name=\"tick\" /></li>\n" )
302 elif re.search( " - FAIL$", line ):
303 self.log.wiki( "<li>" + line + " <ac:emoticon ac:name=\"cross\" /></li>\n" )
304 elif re.search( " - No Result$", line ):
305 self.log.wiki( "<li>" + line + " <ac:emoticon ac:name=\"warning\" /></li>\n" )
306 else: # Substep
307 if not subcaseMessage: # Open Failure Message Printout
308 self.log.wiki( "<ul><li>" + line + "</li>\n" )
309 subcaseMessage = True
310 else: # Add to Failure Message Printout
311 self.log.wiki( "<li>" + line + "</li>\n" )
acsmars27e62dd2015-10-06 11:35:47 -0700312 if subcaseMessage: # End of Failure Message Printout for last item
313 self.log.wiki( "</ul>\n" )
kelvin-onlabf70fd542015-05-07 18:41:40 -0700314 self.log.wiki( "</ul>" )
315 self.log.summary( self.stepCache )
316 self.stepCache = ""
adminbae64d82013-08-01 10:50:15 -0700317 return result
kelvin-onlabf70fd542015-05-07 18:41:40 -0700318
Jon Hall714eeba2015-09-29 17:53:10 -0700319 def runStep( self, code, testCaseNumber ):
adminbae64d82013-08-01 10:50:15 -0700320 if not cli.pause:
Jon Hall5a72b712015-09-28 12:20:59 -0700321 try:
322 step = self.stepCount
323 # stepResults format: ( stepNo, stepName, stepResult, onFail )
324 # NOTE: This is needed to catch results of main.step()'s
325 # called inside functions or loops
326 self.stepResults = ( [], [], [], [] )
adminbae64d82013-08-01 10:50:15 -0700327 exec code[testCaseNumber][step] in module.__dict__
328 self.stepCount = self.stepCount + 1
Jon Hall96b816f2015-11-03 12:00:56 -0800329 self.parseStepResults( testCaseNumber )
Jon Halle234cc42015-08-31 15:26:47 -0700330 except StopIteration: # Raised in self.skipCase()
331 self.log.warn( "Skipping the rest of CASE" +
332 str( testCaseNumber ) )
Jon Hall96b816f2015-11-03 12:00:56 -0800333 self.parseStepResults( testCaseNumber )
Jon Hall714eeba2015-09-29 17:53:10 -0700334 self.stepResultsList.append( self.STEPRESULT )
Jon Halle234cc42015-08-31 15:26:47 -0700335 self.stepCache += "\t\t" + self.onFailMsg + "\n"
336 self.stepCount = self.stepCount + 1
337 return self.FALSE
Jon Hallc1606352015-10-06 14:51:36 -0700338 except StandardError as e:
339 try:
340 stepNo = self.stepResults[0][ self.stepNumber - 1 ]
341 except IndexError:
342 stepNo = "<IndexError>"
343 main.log.warn( "Error trying to get step number. " +
344 "It is likely between step " +
Jon Hall6e709752016-02-01 13:38:46 -0800345 str( self.stepNumber ) + " and step " +
Jon Hallc1606352015-10-06 14:51:36 -0700346 str( self.stepNumber + 1 ) )
347 try:
348 stepName = self.stepResults[1][ self.stepNumber - 1 ]
349 except IndexError:
350 stepName = "<IndexError>"
351 self.log.error( "\nException in the following section of" +
352 " code: " + str( testCaseNumber ) + "." +
353 str( stepNo ) + ": " + stepName )
354 self.log.error( e )
adminbae64d82013-08-01 10:50:15 -0700355 self.stepCount = self.stepCount + 1
Jon Hall714eeba2015-09-29 17:53:10 -0700356 self.logger.updateCaseResults( self )
357 # WIKI results
kelvin-onlabf70fd542015-05-07 18:41:40 -0700358 self.log.wiki( "<ul>" )
359 for line in self.stepCache.splitlines():
360 if re.search( " - PASS$", line ):
361 self.log.wiki( "<li>" + line + " <ac:emoticon ac:name=\"tick\" /></li>\n" )
362 elif re.search( " - FAIL$", line ):
363 self.log.wiki( "<li>" + line + " <ac:emoticon ac:name=\"cross\" /></li>\n" )
364 elif re.search( " - No Result$", line ):
365 self.log.wiki( "<li>" + line + " <ac:emoticon ac:name=\"warning\" /></li>\n" )
Jon Hall90627612015-06-09 14:57:02 -0700366 else: # Should only be on fail message
367 self.log.wiki( "<ul><li>" + line + "</li></ul>\n" )
kelvin-onlabf70fd542015-05-07 18:41:40 -0700368 self.log.wiki( "</ul>" )
Jon Hall714eeba2015-09-29 17:53:10 -0700369 # summary results
kelvin-onlabf70fd542015-05-07 18:41:40 -0700370 self.log.summary( self.stepCache )
371 self.stepCache = ""
shahshreya957feaa2015-03-23 16:08:29 -0700372 self.cleanup()
Jon Hall00539b12015-04-03 13:55:46 -0700373 self.exit()
Jon Halle234cc42015-08-31 15:26:47 -0700374 return self.TRUE
adminbae64d82013-08-01 10:50:15 -0700375 if cli.stop:
376 cli.stop = False
adminbae64d82013-08-01 10:50:15 -0700377 self.TOTAL_TC_NORESULT = self.TOTAL_TC_NORESULT + 1
Jon Hall714eeba2015-09-29 17:53:10 -0700378 self.testCaseResult[str( self.CurrentTestCaseNumber )] = "Stopped"
379 self.logger.updateCaseResults( self )
adminbae64d82013-08-01 10:50:15 -0700380 result = self.cleanup()
Jon Halle234cc42015-08-31 15:26:47 -0700381 return self.FALSE
382
Jon Hall96b816f2015-11-03 12:00:56 -0800383 def parseStepResults( self, testCaseNumber ):
384 """
385 Parse throught the step results for the wiki
386 """
387 try:
388 # Iterate through each of the steps and print them
389 for index in range( len( self.stepResults[0] ) ):
390 # stepResults = ( stepNo, stepName, stepResult, onFail )
391 stepNo = self.stepResults[0][ index ]
392 stepName = self.stepResults[1][ index ]
393 stepResult = self.stepResults[2][ index ]
394 onFail = self.stepResults[3][ index ]
395 self.stepCache += "\t" + str( testCaseNumber ) + "."
396 self.stepCache += str( stepNo ) + " "
397 self.stepCache += stepName + " - "
398 if stepResult == self.TRUE:
399 self.stepCache += "PASS\n"
400 elif stepResult == self.FALSE:
401 self.stepCache += "FAIL\n"
402 self.stepCache += "\t\t" + onFail + "\n"
403 else:
404 self.stepCache += "No Result\n"
405 self.stepResultsList.append( stepResult )
406 except Exception:
407 self.log.exception( "Error parsing step results" )
408
Jon Halle234cc42015-08-31 15:26:47 -0700409 def skipCase( self, result="DEFAULT", msg=None ):
410 """
411 Will skip the rest of the code in a test case. The case results will be
412 determined as normal based on completed assertions unless the result
413 argument is given.
414
415 Optional Arguments:
416 result: Case insensite string. Can be 'PASS' or 'FAIL' and will set
417 the case result accordingly.
418 msg: Message to be printed when the case is skipped in the reports.
419 """
420 result = result.upper().strip()
421 if result == "PASS":
422 self.CASERESULT = self.TRUE
423 elif result == "FAIL":
424 self.CASERESULT = self.FALSE
425 self.onFailMsg = "Skipping the rest of this case. "
426 if msg:
427 self.onFailMsg += str( msg )
428 raise StopIteration
kelvin-onlabf70fd542015-05-07 18:41:40 -0700429
Jon Hall714eeba2015-09-29 17:53:10 -0700430 def addCaseHeader( self ):
431 caseHeader = "\n" + "*" * 30 + "\n Result summary for Testcase" +\
432 str( self.CurrentTestCaseNumber ) + "\n" + "*" * 30 + "\n"
433 self.log.exact( caseHeader )
434 caseHeader = "\n" + "*" * 40 + "\nStart of Test Case" +\
435 str( self.CurrentTestCaseNumber ) + " : "
adminbae64d82013-08-01 10:50:15 -0700436 for driver in self.componentDictionary.keys():
Jon Hall714eeba2015-09-29 17:53:10 -0700437 vars( self )[driver + 'log'].info( caseHeader )
kelvin-onlabf70fd542015-05-07 18:41:40 -0700438
Jon Hall714eeba2015-09-29 17:53:10 -0700439 def addCaseFooter( self ):
Jon Hall5a72b712015-09-28 12:20:59 -0700440 stepNo = self.stepResults[0][-2]
Jon Hall714eeba2015-09-29 17:53:10 -0700441 if stepNo > 0:
442 previousStep = " " + str( self.CurrentTestCaseNumber ) + "." +\
443 str( stepNo ) + ": " + str( self.stepName )
444 stepHeader = "\n" + "*" * 40 + "\nEnd of Step " + previousStep +\
445 "\n" + "*" * 40 + "\n"
kelvin-onlabf70fd542015-05-07 18:41:40 -0700446
Jon Hall714eeba2015-09-29 17:53:10 -0700447 caseFooter = "\n" + "*" * 40 + "\nEnd of Test case " +\
448 str( self.CurrentTestCaseNumber ) + "\n" + "*" * 40 + "\n"
kelvin-onlabf70fd542015-05-07 18:41:40 -0700449
adminbae64d82013-08-01 10:50:15 -0700450 for driver in self.driversList:
Jon Hall714eeba2015-09-29 17:53:10 -0700451 vars( self )[driver].write( stepHeader + "\n" + caseFooter )
adminbae64d82013-08-01 10:50:15 -0700452
Jon Hall714eeba2015-09-29 17:53:10 -0700453 def cleanup( self ):
adminbae64d82013-08-01 10:50:15 -0700454 '''
Jon Hall5b586732015-06-11 11:39:39 -0700455 Print a summary of the current test's results then attempt to release
456 all the component handles and the close opened file handles.
adminbae64d82013-08-01 10:50:15 -0700457
Jon Hall5b586732015-06-11 11:39:39 -0700458 This function shouldbe threadsafe such that cleanup will only be
459 executed once per test.
460
461 This will return TRUE if all the component handles and log handles
462 closed properly, else return FALSE.
adminbae64d82013-08-01 10:50:15 -0700463 '''
464 result = self.TRUE
Jon Hall5b586732015-06-11 11:39:39 -0700465 lock = self.cleanupLock
466 if lock.acquire( False ):
467 try:
468 if self.cleanupFlag is False: # First thread to run this
469 self.cleanupFlag = True
Jon Hall0fc0d452015-07-14 09:49:58 -0700470 if self.initiated:
Jon Hall714eeba2015-09-29 17:53:10 -0700471 self.logger.testSummary( self )
Jon Hall892818c2015-10-20 17:58:34 -0700472 components = self.componentDictionary
473 for component in sorted( components,
474 key=lambda item: components[item]['connect_order'],
475 reverse=True ):
Jon Hall714eeba2015-09-29 17:53:10 -0700476 try:
477 tempObject = vars( self )[component]
478 print "Disconnecting from " + str( tempObject.name ) +\
479 ": " + str( tempObject.__class__)
Jon Hall5b586732015-06-11 11:39:39 -0700480 tempObject.disconnect()
Jon Hall1306a562015-09-04 11:21:24 -0700481 except KeyboardInterrupt:
482 pass
483 except KeyError:
484 # Component not created yet
485 self.log.warn( "Could not find the component " +
486 str( component ) )
487 except StandardError:
Jon Hall5b586732015-06-11 11:39:39 -0700488 self.log.exception( "Exception while disconnecting from " +
489 str( component ) )
490 result = self.FALSE
491 # Closing all the driver's session files
492 for driver in self.componentDictionary.keys():
493 try:
Jon Hall714eeba2015-09-29 17:53:10 -0700494 vars( self )[driver].close_log_handles()
Jon Hall1306a562015-09-04 11:21:24 -0700495 except KeyboardInterrupt:
496 pass
497 except KeyError:
498 # Component not created yet
499 self.log.warn( "Could not find the component " +
500 str( driver ) + " while trying to" +
501 " close log file" )
502 except StandardError:
Jon Hall5b586732015-06-11 11:39:39 -0700503 self.log.exception( "Exception while closing log files for " +
504 str( driver ) )
505 result = self.FALSE
506 else:
507 pass # Someone else already ran through this function
508 finally:
509 lock.release()
510 else: # Someone already has a lock
511 # NOTE: This could cause problems if we don't release the lock
512 # correctly
513 lock.acquire() # Wait for the other thread to finish
514 # NOTE: If we don't wait, exit could be called while the thread
515 # with the lock is still cleaning up
516 lock.release()
adminbae64d82013-08-01 10:50:15 -0700517 return result
Jon Halld61331b2015-02-17 16:35:47 -0800518
Jon Hall714eeba2015-09-29 17:53:10 -0700519 def pause( self ):
adminbae64d82013-08-01 10:50:15 -0700520 '''
Jon Hall714eeba2015-09-29 17:53:10 -0700521 This function will pause the test's execution, and will continue after
522 user provide 'resume' command.
adminbae64d82013-08-01 10:50:15 -0700523 '''
524 __builtin__.testthread.pause()
kelvin-onlabf70fd542015-05-07 18:41:40 -0700525
Jon Hall714eeba2015-09-29 17:53:10 -0700526 def onfail( self, *components ):
adminbae64d82013-08-01 10:50:15 -0700527 '''
kelvin-onlabf70fd542015-05-07 18:41:40 -0700528 When test step failed, calling all the components onfail.
adminbae64d82013-08-01 10:50:15 -0700529 '''
adminbae64d82013-08-01 10:50:15 -0700530 if not components:
Jon Hall714eeba2015-09-29 17:53:10 -0700531 try:
adminbae64d82013-08-01 10:50:15 -0700532 for component in self.componentDictionary.keys():
Jon Hall714eeba2015-09-29 17:53:10 -0700533 tempObject = vars( self )[component]
adminbae64d82013-08-01 10:50:15 -0700534 result = tempObject.onfail()
Jon Hall1306a562015-09-04 11:21:24 -0700535 except StandardError as e:
Jon Hall714eeba2015-09-29 17:53:10 -0700536 print str( e )
adminbae64d82013-08-01 10:50:15 -0700537 result = self.FALSE
adminbae64d82013-08-01 10:50:15 -0700538 else:
Jon Hall714eeba2015-09-29 17:53:10 -0700539 try:
adminbae64d82013-08-01 10:50:15 -0700540 for component in components:
Jon Hall714eeba2015-09-29 17:53:10 -0700541 tempObject = vars( self )[component]
adminbae64d82013-08-01 10:50:15 -0700542 result = tempObject.onfail()
Jon Hall1306a562015-09-04 11:21:24 -0700543 except StandardError as e:
Jon Hall714eeba2015-09-29 17:53:10 -0700544 print str( e )
adminbae64d82013-08-01 10:50:15 -0700545 result = self.FALSE
kelvin-onlabf70fd542015-05-07 18:41:40 -0700546
Jon Hall714eeba2015-09-29 17:53:10 -0700547 def getDriverPath( self, driverName ):
adminbae64d82013-08-01 10:50:15 -0700548 '''
Jon Hall714eeba2015-09-29 17:53:10 -0700549 Based on the component 'type' specified in the params , this method
550 will find the absolute path, by recursively searching the name of
551 the component.
552
553 NOTE: This function requires the linux 'find' command.
adminbae64d82013-08-01 10:50:15 -0700554 '''
555 import commands
556
Jon Hall714eeba2015-09-29 17:53:10 -0700557 cmd = "find " + drivers_path + " -name " + driverName + ".py"
558 result = commands.getoutput( cmd )
kelvin-onlabf70fd542015-05-07 18:41:40 -0700559
Jon Hall714eeba2015-09-29 17:53:10 -0700560 result_array = str( result ).split( '\n' )
adminbae64d82013-08-01 10:50:15 -0700561 result_count = 0
kelvin-onlabf70fd542015-05-07 18:41:40 -0700562
adminbae64d82013-08-01 10:50:15 -0700563 for drivers_list in result_array:
Jon Hall714eeba2015-09-29 17:53:10 -0700564 result_count = result_count + 1
565 if result_count > 1:
566 print "Found " + driverName + " " + str( result_count ) + " times:"
567 print str( result_array )
adminbae64d82013-08-01 10:50:15 -0700568 self.exit()
kelvin-onlabf70fd542015-05-07 18:41:40 -0700569
Jon Hall714eeba2015-09-29 17:53:10 -0700570 result = re.sub( "(.*)drivers", "", result )
571 result = re.sub( "\/\/", "/", result )
572 result = re.sub( "\.py", "", result )
573 result = re.sub( "\.pyc", "", result )
574 result = re.sub( "\/", ".", result )
575 result = "drivers" + result
adminbae64d82013-08-01 10:50:15 -0700576 return result
adminbae64d82013-08-01 10:50:15 -0700577
Jon Hall714eeba2015-09-29 17:53:10 -0700578 def step( self, stepDesc ):
adminbae64d82013-08-01 10:50:15 -0700579 '''
580 The step information of the test-case will append to the logs.
581 '''
Jon Hall714eeba2015-09-29 17:53:10 -0700582 previousStep = " " + str( self.CurrentTestCaseNumber ) + "." +\
583 str( self.stepNumber ) + ": " + str( self.stepName )
adminbae64d82013-08-01 10:50:15 -0700584 self.stepName = stepDesc
Jon Hall5a72b712015-09-28 12:20:59 -0700585 self.stepNumber += 1
586 self.stepResults[0].append( self.stepNumber )
587 self.stepResults[1].append( stepDesc )
588 self.stepResults[2].append( self.NORESULT )
589 self.stepResults[3].append( "No on fail message given" )
adminbae64d82013-08-01 10:50:15 -0700590
Jon Hall714eeba2015-09-29 17:53:10 -0700591 stepName = " " + str( self.CurrentTestCaseNumber ) + "." +\
592 str( self.stepNumber ) + ": " + str( stepDesc )
adminbae64d82013-08-01 10:50:15 -0700593 self.log.step(stepName)
594 stepHeader = ""
Jon Hall714eeba2015-09-29 17:53:10 -0700595 line = "\n" + "-" * 45 + "\n"
596 if self.stepNumber > 1:
597 stepHeader = line + "End of Step " + previousStep + line
598 stepHeader += line + "Start of Step" + stepName + line
adminbae64d82013-08-01 10:50:15 -0700599 for driver in self.componentDictionary.keys():
Jon Hall714eeba2015-09-29 17:53:10 -0700600 vars( self )[driver + 'log'].info( stepHeader )
kelvin-onlabf70fd542015-05-07 18:41:40 -0700601
Jon Hall714eeba2015-09-29 17:53:10 -0700602 def case( self, testCaseName ):
adminbae64d82013-08-01 10:50:15 -0700603 '''
604 Test's each test-case information will append to the logs.
605 '''
Jon Halld61331b2015-02-17 16:35:47 -0800606 self.CurrentTestCase = testCaseName
Jon Hall714eeba2015-09-29 17:53:10 -0700607 testCaseName = " " + str( testCaseName )
608 self.log.case( testCaseName )
609 caseHeader = testCaseName + "\n" + "*" * 40 + "\n"
adminbae64d82013-08-01 10:50:15 -0700610 for driver in self.componentDictionary.keys():
Jon Hall714eeba2015-09-29 17:53:10 -0700611 vars( self )[driver + 'log'].info( caseHeader )
kelvin-onlabf70fd542015-05-07 18:41:40 -0700612
Jon Hall714eeba2015-09-29 17:53:10 -0700613 def testDesc( self, description ):
adminbae64d82013-08-01 10:50:15 -0700614 '''
615 Test description will append to the logs.
616 '''
Jon Hall714eeba2015-09-29 17:53:10 -0700617 description = "Test Description : " + str( description )
618 self.log.info( description )
kelvin-onlabf70fd542015-05-07 18:41:40 -0700619
Jon Hall714eeba2015-09-29 17:53:10 -0700620 def _getTest( self ):
adminbae64d82013-08-01 10:50:15 -0700621 '''
Jon Hall714eeba2015-09-29 17:53:10 -0700622 This method will parse the test script to find required test
623 information.
adminbae64d82013-08-01 10:50:15 -0700624 '''
Jon Hall714eeba2015-09-29 17:53:10 -0700625 testFile = self.tests_path + "/" + self.TEST + "/" + self.TEST + ".py"
626 testFileHandler = open( testFile, 'r' )
adminbae64d82013-08-01 10:50:15 -0700627 testFileList = testFileHandler.readlines()
628 testFileHandler.close()
adminbae64d82013-08-01 10:50:15 -0700629 counter = 0
Jon Hall714eeba2015-09-29 17:53:10 -0700630 for index in range( len( testFileList ) ):
631 lineMatch = re.match( '\s+def CASE(\d+)(.*):',
632 testFileList[index],
633 0 )
adminbae64d82013-08-01 10:50:15 -0700634 if lineMatch:
Jon Hall714eeba2015-09-29 17:53:10 -0700635 counter = counter + 1
636 self.TC_PLANNED = len( self.testcases_list )
kelvin-onlabf70fd542015-05-07 18:41:40 -0700637
Jon Hall714eeba2015-09-29 17:53:10 -0700638 def response_parser( self, response, return_format ):
adminbae64d82013-08-01 10:50:15 -0700639 ''' It will load the default response parser '''
640 response_dict = {}
Jon Hall714eeba2015-09-29 17:53:10 -0700641 response_dict = self.response_to_dict( response, return_format )
642 return_format_string = self.dict_to_return_format( response,
643 return_format,
644 response_dict )
adminbae64d82013-08-01 10:50:15 -0700645 return return_format_string
kelvin-onlabf70fd542015-05-07 18:41:40 -0700646
Jon Hall714eeba2015-09-29 17:53:10 -0700647 def response_to_dict( self, response, return_format ):
adminbae64d82013-08-01 10:50:15 -0700648 response_dict = {}
Jon Hall714eeba2015-09-29 17:53:10 -0700649 json_match = re.search( '^\s*{', response )
650 xml_match = re.search( '^\s*\<', response )
651 ini_match = re.search( '^\s*\[', response )
652 if json_match:
653 self.log.info( "Response is in 'JSON' format, converting to '" +
654 return_format + "' format" )
Jon Halld61331b2015-02-17 16:35:47 -0800655 # Formatting the json string
Jon Hall714eeba2015-09-29 17:53:10 -0700656 response = re.sub( r"{\s*'?(\w)", r'{"\1', response )
657 response = re.sub( r",\s*'?(\w)", r',"\1', response )
658 response = re.sub( r"(\w)'?\s*:", r'\1":', response )
659 response = re.sub( r":\s*'(\w)'\s*([,}])", r':"\1"\2', response )
660 try:
adminbae64d82013-08-01 10:50:15 -0700661 import json
Jon Hall714eeba2015-09-29 17:53:10 -0700662 response_dict = json.loads( response )
Jon Hall1306a562015-09-04 11:21:24 -0700663 except StandardError:
Jon Hall2a5002c2015-08-21 16:49:11 -0700664 self.log.exception( "Json Parser is unable to parse the string" )
adminbae64d82013-08-01 10:50:15 -0700665 return response_dict
Jon Hall714eeba2015-09-29 17:53:10 -0700666 elif ini_match:
667 self.log.info( "Response is in 'INI' format, converting to '" +
668 return_format + "' format" )
adminbae64d82013-08-01 10:50:15 -0700669 from configobj import ConfigObj
Jon Hall714eeba2015-09-29 17:53:10 -0700670 response_file = open( "respnse_file.temp", 'w' )
671 response_file.write( response )
Jon Halld61331b2015-02-17 16:35:47 -0800672 response_file.close()
Jon Hall714eeba2015-09-29 17:53:10 -0700673 response_dict = ConfigObj( "respnse_file.temp" )
adminbae64d82013-08-01 10:50:15 -0700674 return response_dict
Jon Hall714eeba2015-09-29 17:53:10 -0700675 elif xml_match:
676 self.log.info( "Response is in 'XML' format, converting to '" +
677 return_format + "' format" )
678 try:
679 response_dict = xmldict.xml_to_dict( "<response> " +
680 str( response ) +
681 " </response>" )
Jon Hall1306a562015-09-04 11:21:24 -0700682 except StandardError:
683 self.log.exception()
adminbae64d82013-08-01 10:50:15 -0700684 return response_dict
kelvin-onlabf70fd542015-05-07 18:41:40 -0700685
Jon Hall714eeba2015-09-29 17:53:10 -0700686 def dict_to_return_format( self, response, return_format, response_dict ):
687 if return_format == 'table':
adminbae64d82013-08-01 10:50:15 -0700688 ''' Will return in table format'''
689 to_do = "Call the table output formatter"
690 global response_table
691 response_table = '\n'
Jon Hall714eeba2015-09-29 17:53:10 -0700692 response_table = response_table + '\t'.join( response_dict ) + "\n"
kelvin-onlabf70fd542015-05-07 18:41:40 -0700693
Jon Hall714eeba2015-09-29 17:53:10 -0700694 def get_table( value_to_convert ):
695 ''' This will parse the dictionary recusrsively and print as
696 table format'''
adminbae64d82013-08-01 10:50:15 -0700697 table_data = ""
Jon Hall714eeba2015-09-29 17:53:10 -0700698 if isinstance( value_to_convert, dict ):
699 table_data = table_data + '\t'.join( value_to_convert ) +\
700 "\n"
701 for temp_val in value_to_convert.values():
702 table_data = table_data + get_table( temp_val )
703 else:
704 table_data = table_data + str( value_to_convert ) + "\t"
Jon Halld61331b2015-02-17 16:35:47 -0800705 return table_data
kelvin-onlabf70fd542015-05-07 18:41:40 -0700706
Jon Hall714eeba2015-09-29 17:53:10 -0700707 for value in response_dict.values():
708 response_table = response_table + get_table( value )
adminbae64d82013-08-01 10:50:15 -0700709 return response_table
kelvin-onlabf70fd542015-05-07 18:41:40 -0700710
Jon Hall714eeba2015-09-29 17:53:10 -0700711 elif return_format == 'config':
adminbae64d82013-08-01 10:50:15 -0700712 ''' Will return in config format'''
713 to_do = 'Call dict to config coverter'
Jon Hall714eeba2015-09-29 17:53:10 -0700714 response_string = str( response_dict )
adminbae64d82013-08-01 10:50:15 -0700715 print response_string
Jon Hall714eeba2015-09-29 17:53:10 -0700716 response_config = re.sub( ",", "\n\t", response_string )
717 response_config = re.sub( "u\'", "\'", response_config )
718 response_config = re.sub( "{", "", response_config )
719 response_config = re.sub( "}", "\n", response_config )
720 response_config = re.sub( ":", " =", response_config )
721 return "[response]\n\t " + response_config
adminbae64d82013-08-01 10:50:15 -0700722 elif return_format == 'xml':
723 ''' Will return in xml format'''
Jon Hall714eeba2015-09-29 17:53:10 -0700724 response_xml = xmldict.dict_to_xml( response_dict )
725 response_xml = re.sub( ">\s*<", ">\n<", response_xml )
726 return "\n" + response_xml
adminbae64d82013-08-01 10:50:15 -0700727 elif return_format == 'json':
728 ''' Will return in json format'''
729 to_do = 'Call dict to xml coverter'
730 import json
Jon Hall714eeba2015-09-29 17:53:10 -0700731 response_json = json.dumps( response_dict )
adminbae64d82013-08-01 10:50:15 -0700732 return response_json
kelvin-onlabf70fd542015-05-07 18:41:40 -0700733
Jon Hall714eeba2015-09-29 17:53:10 -0700734 def get_random( self ):
adminbae64d82013-08-01 10:50:15 -0700735 self.random_order = self.random_order + 1
736 return self.random_order
kelvin-onlabf70fd542015-05-07 18:41:40 -0700737
Jon Hall714eeba2015-09-29 17:53:10 -0700738 def exit( self ):
adminbae64d82013-08-01 10:50:15 -0700739 __builtin__.testthread = None
Jon Hall5b586732015-06-11 11:39:39 -0700740 for thread in threading.enumerate():
741 if thread.isAlive():
742 try:
743 thread._Thread__stop()
744 except:
Jon Hall1306a562015-09-04 11:21:24 -0700745 # NOTE: We should catch any exceptions while trying to
746 # close the thread so that we can try to close the other
747 # threads as well
Jon Hall714eeba2015-09-29 17:53:10 -0700748 print str( thread.getName() ) +\
749 ' could not be terminated'
adminbae64d82013-08-01 10:50:15 -0700750 sys.exit()
751
Jon Hallcd3d2a32015-10-01 11:07:28 -0700752 def stop( self, email=False ):
753 """
754 Stop the test until Ctrl-D is entered.
755 Ctrl-C will kill the test
Jon Hall25079782015-10-13 13:54:39 -0700756
757 Optional arguments:
758 email can either be a bool, or you can specify the email address
759 to send the email to
Jon Hallcd3d2a32015-10-01 11:07:28 -0700760 """
761 try:
762 if email:
Jon Hall25079782015-10-13 13:54:39 -0700763 if '@' in email:
764 main.mail = email
765 utilities.send_warning_email()
Jon Hallcd3d2a32015-10-01 11:07:28 -0700766 self.log.error( "Test execution suspended. Press Ctrl-D to "
767 "resume or Ctrl-C to exit the test" )
768 # NOTE: Ctrl-D needs to be entered on a new line
769 while True:
770 # TODO: we could give the user an interactive prompt where
771 # they could call functions
772 raw_input()
773 except EOFError:
774 return
775 # Pass all other exceptions up to caller
776
777
Jon Hall714eeba2015-09-29 17:53:10 -0700778def verifyOptions( options ):
adminbae64d82013-08-01 10:50:15 -0700779 '''
Jon Hall714eeba2015-09-29 17:53:10 -0700780 This will verify the command line options and set to default values,
781 if any option not given in command line.
adminbae64d82013-08-01 10:50:15 -0700782 '''
Jon Hall714eeba2015-09-29 17:53:10 -0700783 verifyTest( options )
784 verifyExample( options )
785 verifyTestScript( options )
adminbae64d82013-08-01 10:50:15 -0700786 verifyParams()
Jon Hall714eeba2015-09-29 17:53:10 -0700787 verifyLogdir( options )
788 verifyMail( options )
789 verifyTestCases( options )
790 verifyOnosCell( options )
adminbae64d82013-08-01 10:50:15 -0700791
Jon Hall714eeba2015-09-29 17:53:10 -0700792def verifyTest( options ):
Jon Hall44506242015-07-29 17:40:26 -0700793 try:
794 if options.testname:
795 main.TEST = options.testname
Jon Hall714eeba2015-09-29 17:53:10 -0700796 main.classPath = "tests." + main.TEST + "." + main.TEST
Jon Hall44506242015-07-29 17:40:26 -0700797 main.tests_path = tests_path
798 elif options.example:
799 main.TEST = options.example
Jon Hall714eeba2015-09-29 17:53:10 -0700800 main.tests_path = path + "/examples/"
801 main.classPath = "examples." + main.TEST + "." + main.TEST
Jon Hall44506242015-07-29 17:40:26 -0700802 except AttributeError:
adminbae64d82013-08-01 10:50:15 -0700803 print "Test or Example not specified please specify the --test <test name > or --example <example name>"
Jon Hall5b586732015-06-11 11:39:39 -0700804 main.exit()
adminbae64d82013-08-01 10:50:15 -0700805
Jon Hall714eeba2015-09-29 17:53:10 -0700806def verifyExample( options ):
adminbae64d82013-08-01 10:50:15 -0700807 if options.example:
Jon Hall714eeba2015-09-29 17:53:10 -0700808 main.testDir = path + '/examples/'
809 main.tests_path = path + "/examples/"
810 main.classPath = "examples." + main.TEST + "." + main.TEST
kelvin-onlabf70fd542015-05-07 18:41:40 -0700811
Jon Hall714eeba2015-09-29 17:53:10 -0700812def verifyLogdir( options ):
Jon Hall88e498c2015-03-06 09:54:35 -0800813 # Verifying Log directory option
adminbae64d82013-08-01 10:50:15 -0700814 if options.logdir:
815 main.logdir = options.logdir
Jon Hall714eeba2015-09-29 17:53:10 -0700816 else:
Jon Halld61331b2015-02-17 16:35:47 -0800817 main.logdir = main.FALSE
kelvin-onlabf70fd542015-05-07 18:41:40 -0700818
Jon Hall714eeba2015-09-29 17:53:10 -0700819def verifyMail( options ):
Jon Hall25079782015-10-13 13:54:39 -0700820 # Mail-To: field
821 if options.mail: # Test run specific
adminbae64d82013-08-01 10:50:15 -0700822 main.mail = options.mail
Jon Hall25079782015-10-13 13:54:39 -0700823 elif main.params.get('mail'): # Test suite specific
824 main.mail = main.params.get( 'mail' )
825 else: # TestON specific
826 main.mail = main.config['config'].get( 'mail_to' )
827 # Mail-From: field
828 main.sender = main.config['config'].get( 'mail_from' )
829 # Mail smtp server
830 main.smtp = main.config['config'].get( 'mail_server' )
831 # Mail-From account password
832 main.senderPwd = main.config['config'].get( 'mail_pass' )
833
adminbae64d82013-08-01 10:50:15 -0700834
Jon Hall714eeba2015-09-29 17:53:10 -0700835def verifyTestCases( options ):
Jon Hall88e498c2015-03-06 09:54:35 -0800836 # Getting Test cases list
adminbae64d82013-08-01 10:50:15 -0700837 if options.testcases:
Jon Hallfebb1c72015-03-05 13:30:09 -0800838 testcases_list = options.testcases
Jon Hall88e498c2015-03-06 09:54:35 -0800839 # sys.exit()
Jon Hall714eeba2015-09-29 17:53:10 -0700840 testcases_list = re.sub( "(\[|\])", "", options.testcases )
841 main.testcases_list = eval( testcases_list + "," )
842 else:
adminbae64d82013-08-01 10:50:15 -0700843 if 'testcases' in main.params.keys():
Jon Hall714eeba2015-09-29 17:53:10 -0700844 temp = eval( main.params['testcases'] + "," )
845 list1 = []
846 if isinstance( temp[0], list ):
Jon Hallfebb1c72015-03-05 13:30:09 -0800847 for test in temp:
848 for testcase in test:
Jon Hall714eeba2015-09-29 17:53:10 -0700849 if isinstance( testcase, int ):
850 testcase = [testcase]
851 list1.extend( testcase )
852 else:
853 temp = list( temp )
Jon Hallfebb1c72015-03-05 13:30:09 -0800854 for testcase in temp:
Jon Hall714eeba2015-09-29 17:53:10 -0700855 if isinstance( testcase, int ):
856 testcase = [testcase]
857 list1.extend( testcase )
858 main.testcases_list = list1
859 else:
860 print "Testcases not specifed in params, please provide in " +\
861 "params file or 'testcases' commandline argument"
Jon Halld61331b2015-02-17 16:35:47 -0800862 sys.exit()
kelvin-onlabf70fd542015-05-07 18:41:40 -0700863
Jon Hall714eeba2015-09-29 17:53:10 -0700864def verifyOnosCell( options ):
Hari Krishnabe4b97b2015-07-15 12:19:43 -0700865 # Verifying onoscell option
Hari Krishna03f530e2015-07-10 17:28:27 -0700866 if options.onoscell:
867 main.onoscell = options.onoscell
Hari Krishnabe4b97b2015-07-15 12:19:43 -0700868 main.onosIPs = []
869 main.mnIP = ""
Jon Hall714eeba2015-09-29 17:53:10 -0700870 cellCMD = ". ~/.profile; cell " + main.onoscell
871 output = subprocess.check_output( ["bash", '-c', cellCMD] )
Hari Krishnabe4b97b2015-07-15 12:19:43 -0700872 splitOutput = output.splitlines()
Jon Hall714eeba2015-09-29 17:53:10 -0700873 for i in range( len( splitOutput ) ):
874 if re.match( "OCN", splitOutput[i] ):
875 mnNode = splitOutput[i].split( "=" )
Hari Krishnabe4b97b2015-07-15 12:19:43 -0700876 main.mnIP = mnNode[1]
Jon Hall714eeba2015-09-29 17:53:10 -0700877 # cell already sorts OC variables in bash, so no need to
878 # sort in TestON
879 if re.match( "OC[1-9]", splitOutput[i] ):
880 onosNodes = splitOutput[i].split( "=" )
Hari Krishnabe4b97b2015-07-15 12:19:43 -0700881 main.onosIPs.append( onosNodes[1] )
Jon Hall714eeba2015-09-29 17:53:10 -0700882 else:
Hari Krishna03f530e2015-07-10 17:28:27 -0700883 main.onoscell = main.FALSE
884
Jon Hall714eeba2015-09-29 17:53:10 -0700885def verifyTestScript( options ):
adminbae64d82013-08-01 10:50:15 -0700886 '''
887 Verifyies test script.
888 '''
Jon Halld61331b2015-02-17 16:35:47 -0800889 main.openspeak = openspeak.OpenSpeak()
Jon Hall714eeba2015-09-29 17:53:10 -0700890 openspeakfile = main.testDir + "/" + main.TEST + "/" + main.TEST + ".ospk"
891 testfile = main.testDir + "/" + main.TEST + "/" + main.TEST + ".py"
892 if os.path.exists( openspeakfile ):
Jon Hall44506242015-07-29 17:40:26 -0700893 # Openspeak file found, compiling to python
Jon Hall714eeba2015-09-29 17:53:10 -0700894 main.openspeak.compiler( openspeakfile=openspeakfile, writetofile=1 )
895 elif os.path.exists( testfile ):
Jon Hall44506242015-07-29 17:40:26 -0700896 # No openspeak found, using python file instead
897 pass
adminbae64d82013-08-01 10:50:15 -0700898 else:
Jon Hall714eeba2015-09-29 17:53:10 -0700899 print "\nThere is no \"" + main.TEST + "\" test script.\nPlease provide a " +\
Jon Hall44506242015-07-29 17:40:26 -0700900 "Python or OpenSpeak test script in the tests folder: " +\
Jon Hall714eeba2015-09-29 17:53:10 -0700901 main.testDir + "/" + main.TEST + "/"
adminbae64d82013-08-01 10:50:15 -0700902 __builtin__.testthread = None
903 main.exit()
Jon Hall714eeba2015-09-29 17:53:10 -0700904 try:
905 testModule = __import__( main.classPath,
906 globals(),
907 locals(),
908 [main.TEST],
909 -1 )
Jon Hall1306a562015-09-04 11:21:24 -0700910 except ImportError:
Jon Hall714eeba2015-09-29 17:53:10 -0700911 print "There was an import error, it might mean that there is " +\
912 "no test named " + main.TEST
Jon Halld61331b2015-02-17 16:35:47 -0800913 main.exit()
adminbae64d82013-08-01 10:50:15 -0700914
Jon Hall714eeba2015-09-29 17:53:10 -0700915 testClass = getattr( testModule, main.TEST )
adminbae64d82013-08-01 10:50:15 -0700916 main.testObject = testClass()
917 load_parser()
Jon Hall714eeba2015-09-29 17:53:10 -0700918 main.params = main.parser.parseParams( main.classPath )
919 main.topology = main.parser.parseTopology( main.classPath )
kelvin-onlabf70fd542015-05-07 18:41:40 -0700920
adminbae64d82013-08-01 10:50:15 -0700921def verifyParams():
Jon Hall714eeba2015-09-29 17:53:10 -0700922 try:
adminbae64d82013-08-01 10:50:15 -0700923 main.params = main.params['PARAMS']
Jon Hall1306a562015-09-04 11:21:24 -0700924 except KeyError:
Jon Hall714eeba2015-09-29 17:53:10 -0700925 print "Error with the params file: Either the file not specified " +\
926 "or the format is not correct"
Jon Halld61331b2015-02-17 16:35:47 -0800927 main.exit()
Jon Hall714eeba2015-09-29 17:53:10 -0700928 try:
adminbae64d82013-08-01 10:50:15 -0700929 main.topology = main.topology['TOPOLOGY']
Jon Hall1306a562015-09-04 11:21:24 -0700930 except KeyError:
Jon Hall714eeba2015-09-29 17:53:10 -0700931 print "Error with the Topology file: Either the file not specified " +\
932 "or the format is not correct"
adminbae64d82013-08-01 10:50:15 -0700933 main.exit()
kelvin-onlabf70fd542015-05-07 18:41:40 -0700934
Jon Hall714eeba2015-09-29 17:53:10 -0700935def load_parser():
adminbae64d82013-08-01 10:50:15 -0700936 '''
937 It facilitates the loading customised parser for topology and params file.
938 It loads parser mentioned in tab named parser of teston.cfg file.
Jon Hall714eeba2015-09-29 17:53:10 -0700939 It also loads default xmlparser if no parser have specified in teston.cfg
940 file.
adminbae64d82013-08-01 10:50:15 -0700941
942 '''
943 confighash = main.configDict
Jon Hall714eeba2015-09-29 17:53:10 -0700944 if 'file' in confighash['config']['parser'] and\
945 'class' in confighash['config']['parser']:
Jon Hall44506242015-07-29 17:40:26 -0700946 path = confighash['config']['parser']['file']
Jon Hall714eeba2015-09-29 17:53:10 -0700947 if path is not None or\
948 confighash['config']['parser']['class'] is not None:
Jon Hall44506242015-07-29 17:40:26 -0700949 try:
950 module = re.sub( r".py\s*$", "", path )
adminbae64d82013-08-01 10:50:15 -0700951 moduleList = module.split("/")
Jon Hall714eeba2015-09-29 17:53:10 -0700952 newModule = ".".join( moduleList[-2:] )
Jon Hall44506242015-07-29 17:40:26 -0700953 parsingClass = confighash['config']['parser']['class']
Jon Hall714eeba2015-09-29 17:53:10 -0700954 parsingModule = __import__( newModule,
955 globals(),
956 locals(),
957 [parsingClass],
958 -1 )
959 parsingClass = getattr( parsingModule, parsingClass )
Jon Hall44506242015-07-29 17:40:26 -0700960 main.parser = parsingClass()
Jon Hall714eeba2015-09-29 17:53:10 -0700961 if hasattr( main.parser, "parseParams" ) and\
962 hasattr( main.parser, "parseTopology" ) and\
963 hasattr( main.parser, "parse" ):
Jon Hall44506242015-07-29 17:40:26 -0700964 pass
965 else:
966 print "Invalid parser format"
adminbae64d82013-08-01 10:50:15 -0700967 main.exit()
Jon Hall44506242015-07-29 17:40:26 -0700968 except ImportError:
Jon Hall714eeba2015-09-29 17:53:10 -0700969 print "Could not find the file " + path +\
970 " using default parser."
Jon Halld61331b2015-02-17 16:35:47 -0800971 load_defaultParser()
Jon Hall714eeba2015-09-29 17:53:10 -0700972 elif confighash['config']['parser']['file'] is None or\
973 confighash['config']['parser']['class'] is None:
Jon Halld61331b2015-02-17 16:35:47 -0800974 load_defaultParser()
adminbae64d82013-08-01 10:50:15 -0700975 else:
976 load_defaultParser()
977
978def load_defaultParser():
979 '''
Jon Hall714eeba2015-09-29 17:53:10 -0700980 It will load the default parser which is xml parser to parse the params and
981 topology file.
adminbae64d82013-08-01 10:50:15 -0700982 '''
983 moduleList = main.parserPath.split("/")
Jon Hall714eeba2015-09-29 17:53:10 -0700984 newModule = ".".join( moduleList[-2:] )
985 try:
Jon Halld61331b2015-02-17 16:35:47 -0800986 parsingClass = main.parsingClass
Jon Hall714eeba2015-09-29 17:53:10 -0700987 parsingModule = __import__( newModule,
988 globals(),
989 locals(),
990 [parsingClass],
991 -1 )
992 parsingClass = getattr( parsingModule, parsingClass )
adminbae64d82013-08-01 10:50:15 -0700993 main.parser = parsingClass()
Jon Hall714eeba2015-09-29 17:53:10 -0700994 if hasattr( main.parser, "parseParams" ) and\
995 hasattr( main.parser, "parseTopology" ) and\
996 hasattr( main.parser, "parse" ):
adminbae64d82013-08-01 10:50:15 -0700997 pass
998 else:
999 main.exit()
adminbae64d82013-08-01 10:50:15 -07001000 except ImportError:
1001 print sys.exc_info()[1]
1002
Jon Hall714eeba2015-09-29 17:53:10 -07001003def load_logger():
adminbae64d82013-08-01 10:50:15 -07001004 '''
1005 It facilitates the loading customised parser for topology and params file.
1006 It loads parser mentioned in tab named parser of teston.cfg file.
Jon Hall714eeba2015-09-29 17:53:10 -07001007 It also loads default xmlparser if no parser have specified in teston.cfg
1008 file.
adminbae64d82013-08-01 10:50:15 -07001009 '''
1010 confighash = main.configDict
Jon Hall714eeba2015-09-29 17:53:10 -07001011 if 'file' in confighash['config']['logger'] and\
1012 'class' in confighash['config']['logger']:
Jon Hall44506242015-07-29 17:40:26 -07001013 path = confighash['config']['logger']['file']
Jon Hall714eeba2015-09-29 17:53:10 -07001014 if path is not None or\
1015 confighash['config']['logger']['class'] is not None:
Jon Hall44506242015-07-29 17:40:26 -07001016 try:
1017 module = re.sub( r".py\s*$", "", path )
Jon Hall714eeba2015-09-29 17:53:10 -07001018 moduleList = module.split( "/" )
1019 newModule = ".".join( moduleList[-2:] )
Jon Hall44506242015-07-29 17:40:26 -07001020 loggerClass = confighash['config']['logger']['class']
Jon Hall714eeba2015-09-29 17:53:10 -07001021 loggerModule = __import__( newModule,
1022 globals(),
1023 locals(),
1024 [loggerClass],
1025 -1 )
1026 loggerClass = getattr( loggerModule, loggerClass )
Jon Hall44506242015-07-29 17:40:26 -07001027 main.logger = loggerClass()
Jon Hall44506242015-07-29 17:40:26 -07001028 except ImportError:
Jon Hall714eeba2015-09-29 17:53:10 -07001029 print "Could not find the file " + path +\
1030 " using default logger."
adminbae64d82013-08-01 10:50:15 -07001031 load_defaultlogger()
Jon Hall714eeba2015-09-29 17:53:10 -07001032 elif confighash['config']['parser']['file'] is None or\
1033 confighash['config']['parser']['class'] is None:
Jon Halld61331b2015-02-17 16:35:47 -08001034 load_defaultlogger()
adminbae64d82013-08-01 10:50:15 -07001035 else:
1036 load_defaultlogger()
1037
1038def load_defaultlogger():
1039 '''
Jon Hall714eeba2015-09-29 17:53:10 -07001040 It will load the default parser which is xml parser to parse the params and
1041 topology file.
adminbae64d82013-08-01 10:50:15 -07001042 '''
1043 moduleList = main.loggerPath.split("/")
Jon Hall714eeba2015-09-29 17:53:10 -07001044 newModule = ".".join( moduleList[-2:] )
1045 try:
Jon Halld61331b2015-02-17 16:35:47 -08001046 loggerClass = main.loggerClass
Jon Hall714eeba2015-09-29 17:53:10 -07001047 loggerModule = __import__( newModule,
1048 globals(),
1049 locals(),
1050 [loggerClass],
1051 -1 )
1052 loggerClass = getattr( loggerModule, loggerClass )
adminbae64d82013-08-01 10:50:15 -07001053 main.logger = loggerClass()
1054
1055 except ImportError:
1056 print sys.exc_info()[1]
Jon Halld61331b2015-02-17 16:35:47 -08001057 main.exit()
adminbae64d82013-08-01 10:50:15 -07001058
Jon Hall714eeba2015-09-29 17:53:10 -07001059def _echo( self ):
adminbae64d82013-08-01 10:50:15 -07001060 print "THIS IS ECHO"