blob: cb683dd2ffe7aa7e66710066e4ce865c72130a0a [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 = ( [], [], [], [] )
Jon Hallef822822016-02-19 10:36:47 -0800327 self.log.demo( code[testCaseNumber][step] ) # for ONS Demo
adminbae64d82013-08-01 10:50:15 -0700328 exec code[testCaseNumber][step] in module.__dict__
329 self.stepCount = self.stepCount + 1
Jon Hall96b816f2015-11-03 12:00:56 -0800330 self.parseStepResults( testCaseNumber )
Jon Halle234cc42015-08-31 15:26:47 -0700331 except StopIteration: # Raised in self.skipCase()
332 self.log.warn( "Skipping the rest of CASE" +
333 str( testCaseNumber ) )
Jon Hall96b816f2015-11-03 12:00:56 -0800334 self.parseStepResults( testCaseNumber )
Jon Hall714eeba2015-09-29 17:53:10 -0700335 self.stepResultsList.append( self.STEPRESULT )
Jon Halle234cc42015-08-31 15:26:47 -0700336 self.stepCache += "\t\t" + self.onFailMsg + "\n"
337 self.stepCount = self.stepCount + 1
338 return self.FALSE
Jon Hallc1606352015-10-06 14:51:36 -0700339 except StandardError as e:
340 try:
341 stepNo = self.stepResults[0][ self.stepNumber - 1 ]
342 except IndexError:
343 stepNo = "<IndexError>"
344 main.log.warn( "Error trying to get step number. " +
345 "It is likely between step " +
Jon Hall6e709752016-02-01 13:38:46 -0800346 str( self.stepNumber ) + " and step " +
Jon Hallc1606352015-10-06 14:51:36 -0700347 str( self.stepNumber + 1 ) )
348 try:
349 stepName = self.stepResults[1][ self.stepNumber - 1 ]
350 except IndexError:
351 stepName = "<IndexError>"
352 self.log.error( "\nException in the following section of" +
353 " code: " + str( testCaseNumber ) + "." +
354 str( stepNo ) + ": " + stepName )
355 self.log.error( e )
adminbae64d82013-08-01 10:50:15 -0700356 self.stepCount = self.stepCount + 1
Jon Hall714eeba2015-09-29 17:53:10 -0700357 self.logger.updateCaseResults( self )
358 # WIKI results
kelvin-onlabf70fd542015-05-07 18:41:40 -0700359 self.log.wiki( "<ul>" )
360 for line in self.stepCache.splitlines():
361 if re.search( " - PASS$", line ):
362 self.log.wiki( "<li>" + line + " <ac:emoticon ac:name=\"tick\" /></li>\n" )
363 elif re.search( " - FAIL$", line ):
364 self.log.wiki( "<li>" + line + " <ac:emoticon ac:name=\"cross\" /></li>\n" )
365 elif re.search( " - No Result$", line ):
366 self.log.wiki( "<li>" + line + " <ac:emoticon ac:name=\"warning\" /></li>\n" )
Jon Hall90627612015-06-09 14:57:02 -0700367 else: # Should only be on fail message
368 self.log.wiki( "<ul><li>" + line + "</li></ul>\n" )
kelvin-onlabf70fd542015-05-07 18:41:40 -0700369 self.log.wiki( "</ul>" )
Jon Hall714eeba2015-09-29 17:53:10 -0700370 # summary results
kelvin-onlabf70fd542015-05-07 18:41:40 -0700371 self.log.summary( self.stepCache )
372 self.stepCache = ""
shahshreya957feaa2015-03-23 16:08:29 -0700373 self.cleanup()
Jon Hall00539b12015-04-03 13:55:46 -0700374 self.exit()
Jon Halle234cc42015-08-31 15:26:47 -0700375 return self.TRUE
adminbae64d82013-08-01 10:50:15 -0700376 if cli.stop:
377 cli.stop = False
adminbae64d82013-08-01 10:50:15 -0700378 self.TOTAL_TC_NORESULT = self.TOTAL_TC_NORESULT + 1
Jon Hall714eeba2015-09-29 17:53:10 -0700379 self.testCaseResult[str( self.CurrentTestCaseNumber )] = "Stopped"
380 self.logger.updateCaseResults( self )
adminbae64d82013-08-01 10:50:15 -0700381 result = self.cleanup()
Jon Halle234cc42015-08-31 15:26:47 -0700382 return self.FALSE
383
Jon Hall96b816f2015-11-03 12:00:56 -0800384 def parseStepResults( self, testCaseNumber ):
385 """
386 Parse throught the step results for the wiki
387 """
388 try:
389 # Iterate through each of the steps and print them
390 for index in range( len( self.stepResults[0] ) ):
391 # stepResults = ( stepNo, stepName, stepResult, onFail )
392 stepNo = self.stepResults[0][ index ]
393 stepName = self.stepResults[1][ index ]
394 stepResult = self.stepResults[2][ index ]
395 onFail = self.stepResults[3][ index ]
396 self.stepCache += "\t" + str( testCaseNumber ) + "."
397 self.stepCache += str( stepNo ) + " "
398 self.stepCache += stepName + " - "
399 if stepResult == self.TRUE:
400 self.stepCache += "PASS\n"
401 elif stepResult == self.FALSE:
402 self.stepCache += "FAIL\n"
403 self.stepCache += "\t\t" + onFail + "\n"
404 else:
405 self.stepCache += "No Result\n"
406 self.stepResultsList.append( stepResult )
407 except Exception:
408 self.log.exception( "Error parsing step results" )
409
Jon Halle234cc42015-08-31 15:26:47 -0700410 def skipCase( self, result="DEFAULT", msg=None ):
411 """
412 Will skip the rest of the code in a test case. The case results will be
413 determined as normal based on completed assertions unless the result
414 argument is given.
415
416 Optional Arguments:
417 result: Case insensite string. Can be 'PASS' or 'FAIL' and will set
418 the case result accordingly.
419 msg: Message to be printed when the case is skipped in the reports.
420 """
421 result = result.upper().strip()
422 if result == "PASS":
423 self.CASERESULT = self.TRUE
424 elif result == "FAIL":
425 self.CASERESULT = self.FALSE
426 self.onFailMsg = "Skipping the rest of this case. "
427 if msg:
428 self.onFailMsg += str( msg )
429 raise StopIteration
kelvin-onlabf70fd542015-05-07 18:41:40 -0700430
Jon Hall714eeba2015-09-29 17:53:10 -0700431 def addCaseHeader( self ):
432 caseHeader = "\n" + "*" * 30 + "\n Result summary for Testcase" +\
433 str( self.CurrentTestCaseNumber ) + "\n" + "*" * 30 + "\n"
434 self.log.exact( caseHeader )
435 caseHeader = "\n" + "*" * 40 + "\nStart of Test Case" +\
436 str( self.CurrentTestCaseNumber ) + " : "
adminbae64d82013-08-01 10:50:15 -0700437 for driver in self.componentDictionary.keys():
Jon Hall714eeba2015-09-29 17:53:10 -0700438 vars( self )[driver + 'log'].info( caseHeader )
kelvin-onlabf70fd542015-05-07 18:41:40 -0700439
Jon Hall714eeba2015-09-29 17:53:10 -0700440 def addCaseFooter( self ):
Jon Hall5a72b712015-09-28 12:20:59 -0700441 stepNo = self.stepResults[0][-2]
Jon Hall714eeba2015-09-29 17:53:10 -0700442 if stepNo > 0:
443 previousStep = " " + str( self.CurrentTestCaseNumber ) + "." +\
444 str( stepNo ) + ": " + str( self.stepName )
445 stepHeader = "\n" + "*" * 40 + "\nEnd of Step " + previousStep +\
446 "\n" + "*" * 40 + "\n"
kelvin-onlabf70fd542015-05-07 18:41:40 -0700447
Jon Hall714eeba2015-09-29 17:53:10 -0700448 caseFooter = "\n" + "*" * 40 + "\nEnd of Test case " +\
449 str( self.CurrentTestCaseNumber ) + "\n" + "*" * 40 + "\n"
kelvin-onlabf70fd542015-05-07 18:41:40 -0700450
adminbae64d82013-08-01 10:50:15 -0700451 for driver in self.driversList:
Jon Hall714eeba2015-09-29 17:53:10 -0700452 vars( self )[driver].write( stepHeader + "\n" + caseFooter )
adminbae64d82013-08-01 10:50:15 -0700453
Jon Hall714eeba2015-09-29 17:53:10 -0700454 def cleanup( self ):
adminbae64d82013-08-01 10:50:15 -0700455 '''
Jon Hall5b586732015-06-11 11:39:39 -0700456 Print a summary of the current test's results then attempt to release
457 all the component handles and the close opened file handles.
adminbae64d82013-08-01 10:50:15 -0700458
Jon Hall5b586732015-06-11 11:39:39 -0700459 This function shouldbe threadsafe such that cleanup will only be
460 executed once per test.
461
462 This will return TRUE if all the component handles and log handles
463 closed properly, else return FALSE.
adminbae64d82013-08-01 10:50:15 -0700464 '''
465 result = self.TRUE
Jon Hall5b586732015-06-11 11:39:39 -0700466 lock = self.cleanupLock
467 if lock.acquire( False ):
468 try:
469 if self.cleanupFlag is False: # First thread to run this
470 self.cleanupFlag = True
Jon Hall0fc0d452015-07-14 09:49:58 -0700471 if self.initiated:
Jon Hall714eeba2015-09-29 17:53:10 -0700472 self.logger.testSummary( self )
Jon Hall892818c2015-10-20 17:58:34 -0700473 components = self.componentDictionary
474 for component in sorted( components,
475 key=lambda item: components[item]['connect_order'],
476 reverse=True ):
Jon Hall714eeba2015-09-29 17:53:10 -0700477 try:
478 tempObject = vars( self )[component]
479 print "Disconnecting from " + str( tempObject.name ) +\
480 ": " + str( tempObject.__class__)
Jon Hall5b586732015-06-11 11:39:39 -0700481 tempObject.disconnect()
Jon Hall1306a562015-09-04 11:21:24 -0700482 except KeyboardInterrupt:
483 pass
484 except KeyError:
485 # Component not created yet
486 self.log.warn( "Could not find the component " +
487 str( component ) )
488 except StandardError:
Jon Hall5b586732015-06-11 11:39:39 -0700489 self.log.exception( "Exception while disconnecting from " +
490 str( component ) )
491 result = self.FALSE
492 # Closing all the driver's session files
493 for driver in self.componentDictionary.keys():
494 try:
Jon Hall714eeba2015-09-29 17:53:10 -0700495 vars( self )[driver].close_log_handles()
Jon Hall1306a562015-09-04 11:21:24 -0700496 except KeyboardInterrupt:
497 pass
498 except KeyError:
499 # Component not created yet
500 self.log.warn( "Could not find the component " +
501 str( driver ) + " while trying to" +
502 " close log file" )
503 except StandardError:
Jon Hall5b586732015-06-11 11:39:39 -0700504 self.log.exception( "Exception while closing log files for " +
505 str( driver ) )
506 result = self.FALSE
507 else:
508 pass # Someone else already ran through this function
509 finally:
510 lock.release()
511 else: # Someone already has a lock
512 # NOTE: This could cause problems if we don't release the lock
513 # correctly
514 lock.acquire() # Wait for the other thread to finish
515 # NOTE: If we don't wait, exit could be called while the thread
516 # with the lock is still cleaning up
517 lock.release()
adminbae64d82013-08-01 10:50:15 -0700518 return result
Jon Halld61331b2015-02-17 16:35:47 -0800519
Jon Hall714eeba2015-09-29 17:53:10 -0700520 def pause( self ):
adminbae64d82013-08-01 10:50:15 -0700521 '''
Jon Hall714eeba2015-09-29 17:53:10 -0700522 This function will pause the test's execution, and will continue after
523 user provide 'resume' command.
adminbae64d82013-08-01 10:50:15 -0700524 '''
525 __builtin__.testthread.pause()
kelvin-onlabf70fd542015-05-07 18:41:40 -0700526
Jon Hall714eeba2015-09-29 17:53:10 -0700527 def onfail( self, *components ):
adminbae64d82013-08-01 10:50:15 -0700528 '''
kelvin-onlabf70fd542015-05-07 18:41:40 -0700529 When test step failed, calling all the components onfail.
adminbae64d82013-08-01 10:50:15 -0700530 '''
adminbae64d82013-08-01 10:50:15 -0700531 if not components:
Jon Hall714eeba2015-09-29 17:53:10 -0700532 try:
adminbae64d82013-08-01 10:50:15 -0700533 for component in self.componentDictionary.keys():
Jon Hall714eeba2015-09-29 17:53:10 -0700534 tempObject = vars( self )[component]
adminbae64d82013-08-01 10:50:15 -0700535 result = tempObject.onfail()
Jon Hall1306a562015-09-04 11:21:24 -0700536 except StandardError as e:
Jon Hall714eeba2015-09-29 17:53:10 -0700537 print str( e )
adminbae64d82013-08-01 10:50:15 -0700538 result = self.FALSE
adminbae64d82013-08-01 10:50:15 -0700539 else:
Jon Hall714eeba2015-09-29 17:53:10 -0700540 try:
adminbae64d82013-08-01 10:50:15 -0700541 for component in components:
Jon Hall714eeba2015-09-29 17:53:10 -0700542 tempObject = vars( self )[component]
adminbae64d82013-08-01 10:50:15 -0700543 result = tempObject.onfail()
Jon Hall1306a562015-09-04 11:21:24 -0700544 except StandardError as e:
Jon Hall714eeba2015-09-29 17:53:10 -0700545 print str( e )
adminbae64d82013-08-01 10:50:15 -0700546 result = self.FALSE
kelvin-onlabf70fd542015-05-07 18:41:40 -0700547
Jon Hall714eeba2015-09-29 17:53:10 -0700548 def getDriverPath( self, driverName ):
adminbae64d82013-08-01 10:50:15 -0700549 '''
Jon Hall714eeba2015-09-29 17:53:10 -0700550 Based on the component 'type' specified in the params , this method
551 will find the absolute path, by recursively searching the name of
552 the component.
553
554 NOTE: This function requires the linux 'find' command.
adminbae64d82013-08-01 10:50:15 -0700555 '''
556 import commands
557
Jon Hall714eeba2015-09-29 17:53:10 -0700558 cmd = "find " + drivers_path + " -name " + driverName + ".py"
559 result = commands.getoutput( cmd )
kelvin-onlabf70fd542015-05-07 18:41:40 -0700560
Jon Hall714eeba2015-09-29 17:53:10 -0700561 result_array = str( result ).split( '\n' )
adminbae64d82013-08-01 10:50:15 -0700562 result_count = 0
kelvin-onlabf70fd542015-05-07 18:41:40 -0700563
adminbae64d82013-08-01 10:50:15 -0700564 for drivers_list in result_array:
Jon Hall714eeba2015-09-29 17:53:10 -0700565 result_count = result_count + 1
566 if result_count > 1:
567 print "Found " + driverName + " " + str( result_count ) + " times:"
568 print str( result_array )
adminbae64d82013-08-01 10:50:15 -0700569 self.exit()
kelvin-onlabf70fd542015-05-07 18:41:40 -0700570
Jon Hall714eeba2015-09-29 17:53:10 -0700571 result = re.sub( "(.*)drivers", "", result )
572 result = re.sub( "\/\/", "/", result )
573 result = re.sub( "\.py", "", result )
574 result = re.sub( "\.pyc", "", result )
575 result = re.sub( "\/", ".", result )
576 result = "drivers" + result
adminbae64d82013-08-01 10:50:15 -0700577 return result
adminbae64d82013-08-01 10:50:15 -0700578
Jon Hall714eeba2015-09-29 17:53:10 -0700579 def step( self, stepDesc ):
adminbae64d82013-08-01 10:50:15 -0700580 '''
581 The step information of the test-case will append to the logs.
582 '''
Jon Hall714eeba2015-09-29 17:53:10 -0700583 previousStep = " " + str( self.CurrentTestCaseNumber ) + "." +\
584 str( self.stepNumber ) + ": " + str( self.stepName )
adminbae64d82013-08-01 10:50:15 -0700585 self.stepName = stepDesc
Jon Hall5a72b712015-09-28 12:20:59 -0700586 self.stepNumber += 1
587 self.stepResults[0].append( self.stepNumber )
588 self.stepResults[1].append( stepDesc )
589 self.stepResults[2].append( self.NORESULT )
590 self.stepResults[3].append( "No on fail message given" )
adminbae64d82013-08-01 10:50:15 -0700591
Jon Hall714eeba2015-09-29 17:53:10 -0700592 stepName = " " + str( self.CurrentTestCaseNumber ) + "." +\
593 str( self.stepNumber ) + ": " + str( stepDesc )
adminbae64d82013-08-01 10:50:15 -0700594 self.log.step(stepName)
595 stepHeader = ""
Jon Hall714eeba2015-09-29 17:53:10 -0700596 line = "\n" + "-" * 45 + "\n"
597 if self.stepNumber > 1:
598 stepHeader = line + "End of Step " + previousStep + line
599 stepHeader += line + "Start of Step" + stepName + line
adminbae64d82013-08-01 10:50:15 -0700600 for driver in self.componentDictionary.keys():
Jon Hall714eeba2015-09-29 17:53:10 -0700601 vars( self )[driver + 'log'].info( stepHeader )
kelvin-onlabf70fd542015-05-07 18:41:40 -0700602
Jon Hall714eeba2015-09-29 17:53:10 -0700603 def case( self, testCaseName ):
adminbae64d82013-08-01 10:50:15 -0700604 '''
605 Test's each test-case information will append to the logs.
606 '''
Jon Halld61331b2015-02-17 16:35:47 -0800607 self.CurrentTestCase = testCaseName
Jon Hall714eeba2015-09-29 17:53:10 -0700608 testCaseName = " " + str( testCaseName )
609 self.log.case( testCaseName )
610 caseHeader = testCaseName + "\n" + "*" * 40 + "\n"
adminbae64d82013-08-01 10:50:15 -0700611 for driver in self.componentDictionary.keys():
Jon Hall714eeba2015-09-29 17:53:10 -0700612 vars( self )[driver + 'log'].info( caseHeader )
kelvin-onlabf70fd542015-05-07 18:41:40 -0700613
Jon Hall714eeba2015-09-29 17:53:10 -0700614 def testDesc( self, description ):
adminbae64d82013-08-01 10:50:15 -0700615 '''
616 Test description will append to the logs.
617 '''
Jon Hall714eeba2015-09-29 17:53:10 -0700618 description = "Test Description : " + str( description )
619 self.log.info( description )
kelvin-onlabf70fd542015-05-07 18:41:40 -0700620
Jon Hall714eeba2015-09-29 17:53:10 -0700621 def _getTest( self ):
adminbae64d82013-08-01 10:50:15 -0700622 '''
Jon Hall714eeba2015-09-29 17:53:10 -0700623 This method will parse the test script to find required test
624 information.
adminbae64d82013-08-01 10:50:15 -0700625 '''
Jon Hall714eeba2015-09-29 17:53:10 -0700626 testFile = self.tests_path + "/" + self.TEST + "/" + self.TEST + ".py"
627 testFileHandler = open( testFile, 'r' )
adminbae64d82013-08-01 10:50:15 -0700628 testFileList = testFileHandler.readlines()
629 testFileHandler.close()
adminbae64d82013-08-01 10:50:15 -0700630 counter = 0
Jon Hall714eeba2015-09-29 17:53:10 -0700631 for index in range( len( testFileList ) ):
632 lineMatch = re.match( '\s+def CASE(\d+)(.*):',
633 testFileList[index],
634 0 )
adminbae64d82013-08-01 10:50:15 -0700635 if lineMatch:
Jon Hall714eeba2015-09-29 17:53:10 -0700636 counter = counter + 1
637 self.TC_PLANNED = len( self.testcases_list )
kelvin-onlabf70fd542015-05-07 18:41:40 -0700638
Jon Hall714eeba2015-09-29 17:53:10 -0700639 def response_parser( self, response, return_format ):
adminbae64d82013-08-01 10:50:15 -0700640 ''' It will load the default response parser '''
641 response_dict = {}
Jon Hall714eeba2015-09-29 17:53:10 -0700642 response_dict = self.response_to_dict( response, return_format )
643 return_format_string = self.dict_to_return_format( response,
644 return_format,
645 response_dict )
adminbae64d82013-08-01 10:50:15 -0700646 return return_format_string
kelvin-onlabf70fd542015-05-07 18:41:40 -0700647
Jon Hall714eeba2015-09-29 17:53:10 -0700648 def response_to_dict( self, response, return_format ):
adminbae64d82013-08-01 10:50:15 -0700649 response_dict = {}
Jon Hall714eeba2015-09-29 17:53:10 -0700650 json_match = re.search( '^\s*{', response )
651 xml_match = re.search( '^\s*\<', response )
652 ini_match = re.search( '^\s*\[', response )
653 if json_match:
654 self.log.info( "Response is in 'JSON' format, converting to '" +
655 return_format + "' format" )
Jon Halld61331b2015-02-17 16:35:47 -0800656 # Formatting the json string
Jon Hall714eeba2015-09-29 17:53:10 -0700657 response = re.sub( r"{\s*'?(\w)", r'{"\1', response )
658 response = re.sub( r",\s*'?(\w)", r',"\1', response )
659 response = re.sub( r"(\w)'?\s*:", r'\1":', response )
660 response = re.sub( r":\s*'(\w)'\s*([,}])", r':"\1"\2', response )
661 try:
adminbae64d82013-08-01 10:50:15 -0700662 import json
Jon Hall714eeba2015-09-29 17:53:10 -0700663 response_dict = json.loads( response )
Jon Hall1306a562015-09-04 11:21:24 -0700664 except StandardError:
Jon Hall2a5002c2015-08-21 16:49:11 -0700665 self.log.exception( "Json Parser is unable to parse the string" )
adminbae64d82013-08-01 10:50:15 -0700666 return response_dict
Jon Hall714eeba2015-09-29 17:53:10 -0700667 elif ini_match:
668 self.log.info( "Response is in 'INI' format, converting to '" +
669 return_format + "' format" )
adminbae64d82013-08-01 10:50:15 -0700670 from configobj import ConfigObj
Jon Hall714eeba2015-09-29 17:53:10 -0700671 response_file = open( "respnse_file.temp", 'w' )
672 response_file.write( response )
Jon Halld61331b2015-02-17 16:35:47 -0800673 response_file.close()
Jon Hall714eeba2015-09-29 17:53:10 -0700674 response_dict = ConfigObj( "respnse_file.temp" )
adminbae64d82013-08-01 10:50:15 -0700675 return response_dict
Jon Hall714eeba2015-09-29 17:53:10 -0700676 elif xml_match:
677 self.log.info( "Response is in 'XML' format, converting to '" +
678 return_format + "' format" )
679 try:
680 response_dict = xmldict.xml_to_dict( "<response> " +
681 str( response ) +
682 " </response>" )
Jon Hall1306a562015-09-04 11:21:24 -0700683 except StandardError:
684 self.log.exception()
adminbae64d82013-08-01 10:50:15 -0700685 return response_dict
kelvin-onlabf70fd542015-05-07 18:41:40 -0700686
Jon Hall714eeba2015-09-29 17:53:10 -0700687 def dict_to_return_format( self, response, return_format, response_dict ):
688 if return_format == 'table':
adminbae64d82013-08-01 10:50:15 -0700689 ''' Will return in table format'''
690 to_do = "Call the table output formatter"
691 global response_table
692 response_table = '\n'
Jon Hall714eeba2015-09-29 17:53:10 -0700693 response_table = response_table + '\t'.join( response_dict ) + "\n"
kelvin-onlabf70fd542015-05-07 18:41:40 -0700694
Jon Hall714eeba2015-09-29 17:53:10 -0700695 def get_table( value_to_convert ):
696 ''' This will parse the dictionary recusrsively and print as
697 table format'''
adminbae64d82013-08-01 10:50:15 -0700698 table_data = ""
Jon Hall714eeba2015-09-29 17:53:10 -0700699 if isinstance( value_to_convert, dict ):
700 table_data = table_data + '\t'.join( value_to_convert ) +\
701 "\n"
702 for temp_val in value_to_convert.values():
703 table_data = table_data + get_table( temp_val )
704 else:
705 table_data = table_data + str( value_to_convert ) + "\t"
Jon Halld61331b2015-02-17 16:35:47 -0800706 return table_data
kelvin-onlabf70fd542015-05-07 18:41:40 -0700707
Jon Hall714eeba2015-09-29 17:53:10 -0700708 for value in response_dict.values():
709 response_table = response_table + get_table( value )
adminbae64d82013-08-01 10:50:15 -0700710 return response_table
kelvin-onlabf70fd542015-05-07 18:41:40 -0700711
Jon Hall714eeba2015-09-29 17:53:10 -0700712 elif return_format == 'config':
adminbae64d82013-08-01 10:50:15 -0700713 ''' Will return in config format'''
714 to_do = 'Call dict to config coverter'
Jon Hall714eeba2015-09-29 17:53:10 -0700715 response_string = str( response_dict )
adminbae64d82013-08-01 10:50:15 -0700716 print response_string
Jon Hall714eeba2015-09-29 17:53:10 -0700717 response_config = re.sub( ",", "\n\t", response_string )
718 response_config = re.sub( "u\'", "\'", response_config )
719 response_config = re.sub( "{", "", response_config )
720 response_config = re.sub( "}", "\n", response_config )
721 response_config = re.sub( ":", " =", response_config )
722 return "[response]\n\t " + response_config
adminbae64d82013-08-01 10:50:15 -0700723 elif return_format == 'xml':
724 ''' Will return in xml format'''
Jon Hall714eeba2015-09-29 17:53:10 -0700725 response_xml = xmldict.dict_to_xml( response_dict )
726 response_xml = re.sub( ">\s*<", ">\n<", response_xml )
727 return "\n" + response_xml
adminbae64d82013-08-01 10:50:15 -0700728 elif return_format == 'json':
729 ''' Will return in json format'''
730 to_do = 'Call dict to xml coverter'
731 import json
Jon Hall714eeba2015-09-29 17:53:10 -0700732 response_json = json.dumps( response_dict )
adminbae64d82013-08-01 10:50:15 -0700733 return response_json
kelvin-onlabf70fd542015-05-07 18:41:40 -0700734
Jon Hall714eeba2015-09-29 17:53:10 -0700735 def get_random( self ):
adminbae64d82013-08-01 10:50:15 -0700736 self.random_order = self.random_order + 1
737 return self.random_order
kelvin-onlabf70fd542015-05-07 18:41:40 -0700738
Jon Hall714eeba2015-09-29 17:53:10 -0700739 def exit( self ):
adminbae64d82013-08-01 10:50:15 -0700740 __builtin__.testthread = None
Jon Hall5b586732015-06-11 11:39:39 -0700741 for thread in threading.enumerate():
742 if thread.isAlive():
743 try:
744 thread._Thread__stop()
745 except:
Jon Hall1306a562015-09-04 11:21:24 -0700746 # NOTE: We should catch any exceptions while trying to
747 # close the thread so that we can try to close the other
748 # threads as well
Jon Hall714eeba2015-09-29 17:53:10 -0700749 print str( thread.getName() ) +\
750 ' could not be terminated'
Jon Hallf9572352016-03-09 10:21:18 -0800751 demoFile = open(main.DemoCodeFileName,"w+")
752 demoFile.write( "\n" * 60 )
753 demoFile.close()
754 logfile = open(main.LogFileName,"w+")
755 logfile.write( "\n" * 60 )
756 logfile.close()
adminbae64d82013-08-01 10:50:15 -0700757 sys.exit()
758
Jon Hallcd3d2a32015-10-01 11:07:28 -0700759 def stop( self, email=False ):
760 """
761 Stop the test until Ctrl-D is entered.
762 Ctrl-C will kill the test
Jon Hall25079782015-10-13 13:54:39 -0700763
764 Optional arguments:
765 email can either be a bool, or you can specify the email address
766 to send the email to
Jon Hallcd3d2a32015-10-01 11:07:28 -0700767 """
768 try:
769 if email:
Jon Hall25079782015-10-13 13:54:39 -0700770 if '@' in email:
771 main.mail = email
772 utilities.send_warning_email()
Jon Hallcd3d2a32015-10-01 11:07:28 -0700773 self.log.error( "Test execution suspended. Press Ctrl-D to "
774 "resume or Ctrl-C to exit the test" )
775 # NOTE: Ctrl-D needs to be entered on a new line
776 while True:
777 # TODO: we could give the user an interactive prompt where
778 # they could call functions
779 raw_input()
780 except EOFError:
781 return
782 # Pass all other exceptions up to caller
783
784
Jon Hall714eeba2015-09-29 17:53:10 -0700785def verifyOptions( options ):
adminbae64d82013-08-01 10:50:15 -0700786 '''
Jon Hall714eeba2015-09-29 17:53:10 -0700787 This will verify the command line options and set to default values,
788 if any option not given in command line.
adminbae64d82013-08-01 10:50:15 -0700789 '''
Jon Hall714eeba2015-09-29 17:53:10 -0700790 verifyTest( options )
791 verifyExample( options )
792 verifyTestScript( options )
adminbae64d82013-08-01 10:50:15 -0700793 verifyParams()
Jon Hall714eeba2015-09-29 17:53:10 -0700794 verifyLogdir( options )
795 verifyMail( options )
796 verifyTestCases( options )
797 verifyOnosCell( options )
adminbae64d82013-08-01 10:50:15 -0700798
Jon Hall714eeba2015-09-29 17:53:10 -0700799def verifyTest( options ):
Jon Hall44506242015-07-29 17:40:26 -0700800 try:
801 if options.testname:
802 main.TEST = options.testname
Jon Hall714eeba2015-09-29 17:53:10 -0700803 main.classPath = "tests." + main.TEST + "." + main.TEST
Jon Hall44506242015-07-29 17:40:26 -0700804 main.tests_path = tests_path
805 elif options.example:
806 main.TEST = options.example
Jon Hall714eeba2015-09-29 17:53:10 -0700807 main.tests_path = path + "/examples/"
808 main.classPath = "examples." + main.TEST + "." + main.TEST
Jon Hall44506242015-07-29 17:40:26 -0700809 except AttributeError:
adminbae64d82013-08-01 10:50:15 -0700810 print "Test or Example not specified please specify the --test <test name > or --example <example name>"
Jon Hall5b586732015-06-11 11:39:39 -0700811 main.exit()
adminbae64d82013-08-01 10:50:15 -0700812
Jon Hall714eeba2015-09-29 17:53:10 -0700813def verifyExample( options ):
adminbae64d82013-08-01 10:50:15 -0700814 if options.example:
Jon Hall714eeba2015-09-29 17:53:10 -0700815 main.testDir = path + '/examples/'
816 main.tests_path = path + "/examples/"
817 main.classPath = "examples." + main.TEST + "." + main.TEST
kelvin-onlabf70fd542015-05-07 18:41:40 -0700818
Jon Hall714eeba2015-09-29 17:53:10 -0700819def verifyLogdir( options ):
Jon Hall88e498c2015-03-06 09:54:35 -0800820 # Verifying Log directory option
adminbae64d82013-08-01 10:50:15 -0700821 if options.logdir:
822 main.logdir = options.logdir
Jon Hall714eeba2015-09-29 17:53:10 -0700823 else:
Jon Halld61331b2015-02-17 16:35:47 -0800824 main.logdir = main.FALSE
kelvin-onlabf70fd542015-05-07 18:41:40 -0700825
Jon Hall714eeba2015-09-29 17:53:10 -0700826def verifyMail( options ):
Jon Hall25079782015-10-13 13:54:39 -0700827 # Mail-To: field
828 if options.mail: # Test run specific
adminbae64d82013-08-01 10:50:15 -0700829 main.mail = options.mail
Jon Hall25079782015-10-13 13:54:39 -0700830 elif main.params.get('mail'): # Test suite specific
831 main.mail = main.params.get( 'mail' )
832 else: # TestON specific
833 main.mail = main.config['config'].get( 'mail_to' )
834 # Mail-From: field
835 main.sender = main.config['config'].get( 'mail_from' )
836 # Mail smtp server
837 main.smtp = main.config['config'].get( 'mail_server' )
838 # Mail-From account password
839 main.senderPwd = main.config['config'].get( 'mail_pass' )
840
adminbae64d82013-08-01 10:50:15 -0700841
Jon Hall714eeba2015-09-29 17:53:10 -0700842def verifyTestCases( options ):
Jon Hall88e498c2015-03-06 09:54:35 -0800843 # Getting Test cases list
adminbae64d82013-08-01 10:50:15 -0700844 if options.testcases:
Jon Hallfebb1c72015-03-05 13:30:09 -0800845 testcases_list = options.testcases
Jon Hall88e498c2015-03-06 09:54:35 -0800846 # sys.exit()
Jon Hall714eeba2015-09-29 17:53:10 -0700847 testcases_list = re.sub( "(\[|\])", "", options.testcases )
848 main.testcases_list = eval( testcases_list + "," )
849 else:
adminbae64d82013-08-01 10:50:15 -0700850 if 'testcases' in main.params.keys():
Jon Hall714eeba2015-09-29 17:53:10 -0700851 temp = eval( main.params['testcases'] + "," )
852 list1 = []
853 if isinstance( temp[0], list ):
Jon Hallfebb1c72015-03-05 13:30:09 -0800854 for test in temp:
855 for testcase in test:
Jon Hall714eeba2015-09-29 17:53:10 -0700856 if isinstance( testcase, int ):
857 testcase = [testcase]
858 list1.extend( testcase )
859 else:
860 temp = list( temp )
Jon Hallfebb1c72015-03-05 13:30:09 -0800861 for testcase in temp:
Jon Hall714eeba2015-09-29 17:53:10 -0700862 if isinstance( testcase, int ):
863 testcase = [testcase]
864 list1.extend( testcase )
865 main.testcases_list = list1
866 else:
867 print "Testcases not specifed in params, please provide in " +\
868 "params file or 'testcases' commandline argument"
Jon Halld61331b2015-02-17 16:35:47 -0800869 sys.exit()
kelvin-onlabf70fd542015-05-07 18:41:40 -0700870
Jon Hall714eeba2015-09-29 17:53:10 -0700871def verifyOnosCell( options ):
Hari Krishnabe4b97b2015-07-15 12:19:43 -0700872 # Verifying onoscell option
Hari Krishna03f530e2015-07-10 17:28:27 -0700873 if options.onoscell:
874 main.onoscell = options.onoscell
Hari Krishnabe4b97b2015-07-15 12:19:43 -0700875 main.onosIPs = []
876 main.mnIP = ""
Jon Hall714eeba2015-09-29 17:53:10 -0700877 cellCMD = ". ~/.profile; cell " + main.onoscell
878 output = subprocess.check_output( ["bash", '-c', cellCMD] )
Hari Krishnabe4b97b2015-07-15 12:19:43 -0700879 splitOutput = output.splitlines()
Jon Hall714eeba2015-09-29 17:53:10 -0700880 for i in range( len( splitOutput ) ):
881 if re.match( "OCN", splitOutput[i] ):
882 mnNode = splitOutput[i].split( "=" )
Hari Krishnabe4b97b2015-07-15 12:19:43 -0700883 main.mnIP = mnNode[1]
Jon Hall714eeba2015-09-29 17:53:10 -0700884 # cell already sorts OC variables in bash, so no need to
885 # sort in TestON
886 if re.match( "OC[1-9]", splitOutput[i] ):
887 onosNodes = splitOutput[i].split( "=" )
Hari Krishnabe4b97b2015-07-15 12:19:43 -0700888 main.onosIPs.append( onosNodes[1] )
Jon Hall714eeba2015-09-29 17:53:10 -0700889 else:
Hari Krishna03f530e2015-07-10 17:28:27 -0700890 main.onoscell = main.FALSE
891
Jon Hall714eeba2015-09-29 17:53:10 -0700892def verifyTestScript( options ):
adminbae64d82013-08-01 10:50:15 -0700893 '''
894 Verifyies test script.
895 '''
Jon Halld61331b2015-02-17 16:35:47 -0800896 main.openspeak = openspeak.OpenSpeak()
Jon Hall714eeba2015-09-29 17:53:10 -0700897 openspeakfile = main.testDir + "/" + main.TEST + "/" + main.TEST + ".ospk"
898 testfile = main.testDir + "/" + main.TEST + "/" + main.TEST + ".py"
899 if os.path.exists( openspeakfile ):
Jon Hall44506242015-07-29 17:40:26 -0700900 # Openspeak file found, compiling to python
Jon Hall714eeba2015-09-29 17:53:10 -0700901 main.openspeak.compiler( openspeakfile=openspeakfile, writetofile=1 )
902 elif os.path.exists( testfile ):
Jon Hall44506242015-07-29 17:40:26 -0700903 # No openspeak found, using python file instead
904 pass
adminbae64d82013-08-01 10:50:15 -0700905 else:
Jon Hall714eeba2015-09-29 17:53:10 -0700906 print "\nThere is no \"" + main.TEST + "\" test script.\nPlease provide a " +\
Jon Hall44506242015-07-29 17:40:26 -0700907 "Python or OpenSpeak test script in the tests folder: " +\
Jon Hall714eeba2015-09-29 17:53:10 -0700908 main.testDir + "/" + main.TEST + "/"
adminbae64d82013-08-01 10:50:15 -0700909 __builtin__.testthread = None
910 main.exit()
Jon Hall714eeba2015-09-29 17:53:10 -0700911 try:
912 testModule = __import__( main.classPath,
913 globals(),
914 locals(),
915 [main.TEST],
916 -1 )
Jon Hall1306a562015-09-04 11:21:24 -0700917 except ImportError:
Jon Hall714eeba2015-09-29 17:53:10 -0700918 print "There was an import error, it might mean that there is " +\
919 "no test named " + main.TEST
Jon Halld61331b2015-02-17 16:35:47 -0800920 main.exit()
adminbae64d82013-08-01 10:50:15 -0700921
Jon Hall714eeba2015-09-29 17:53:10 -0700922 testClass = getattr( testModule, main.TEST )
adminbae64d82013-08-01 10:50:15 -0700923 main.testObject = testClass()
924 load_parser()
Jon Hall714eeba2015-09-29 17:53:10 -0700925 main.params = main.parser.parseParams( main.classPath )
926 main.topology = main.parser.parseTopology( main.classPath )
kelvin-onlabf70fd542015-05-07 18:41:40 -0700927
adminbae64d82013-08-01 10:50:15 -0700928def verifyParams():
Jon Hall714eeba2015-09-29 17:53:10 -0700929 try:
adminbae64d82013-08-01 10:50:15 -0700930 main.params = main.params['PARAMS']
Jon Hall1306a562015-09-04 11:21:24 -0700931 except KeyError:
Jon Hall714eeba2015-09-29 17:53:10 -0700932 print "Error with the params file: Either the file not specified " +\
933 "or the format is not correct"
Jon Halld61331b2015-02-17 16:35:47 -0800934 main.exit()
Jon Hall714eeba2015-09-29 17:53:10 -0700935 try:
adminbae64d82013-08-01 10:50:15 -0700936 main.topology = main.topology['TOPOLOGY']
Jon Hall1306a562015-09-04 11:21:24 -0700937 except KeyError:
Jon Hall714eeba2015-09-29 17:53:10 -0700938 print "Error with the Topology file: Either the file not specified " +\
939 "or the format is not correct"
adminbae64d82013-08-01 10:50:15 -0700940 main.exit()
kelvin-onlabf70fd542015-05-07 18:41:40 -0700941
Jon Hall714eeba2015-09-29 17:53:10 -0700942def load_parser():
adminbae64d82013-08-01 10:50:15 -0700943 '''
944 It facilitates the loading customised parser for topology and params file.
945 It loads parser mentioned in tab named parser of teston.cfg file.
Jon Hall714eeba2015-09-29 17:53:10 -0700946 It also loads default xmlparser if no parser have specified in teston.cfg
947 file.
adminbae64d82013-08-01 10:50:15 -0700948
949 '''
950 confighash = main.configDict
Jon Hall714eeba2015-09-29 17:53:10 -0700951 if 'file' in confighash['config']['parser'] and\
952 'class' in confighash['config']['parser']:
Jon Hall44506242015-07-29 17:40:26 -0700953 path = confighash['config']['parser']['file']
Jon Hall714eeba2015-09-29 17:53:10 -0700954 if path is not None or\
955 confighash['config']['parser']['class'] is not None:
Jon Hall44506242015-07-29 17:40:26 -0700956 try:
957 module = re.sub( r".py\s*$", "", path )
adminbae64d82013-08-01 10:50:15 -0700958 moduleList = module.split("/")
Jon Hall714eeba2015-09-29 17:53:10 -0700959 newModule = ".".join( moduleList[-2:] )
Jon Hall44506242015-07-29 17:40:26 -0700960 parsingClass = confighash['config']['parser']['class']
Jon Hall714eeba2015-09-29 17:53:10 -0700961 parsingModule = __import__( newModule,
962 globals(),
963 locals(),
964 [parsingClass],
965 -1 )
966 parsingClass = getattr( parsingModule, parsingClass )
Jon Hall44506242015-07-29 17:40:26 -0700967 main.parser = parsingClass()
Jon Hall714eeba2015-09-29 17:53:10 -0700968 if hasattr( main.parser, "parseParams" ) and\
969 hasattr( main.parser, "parseTopology" ) and\
970 hasattr( main.parser, "parse" ):
Jon Hall44506242015-07-29 17:40:26 -0700971 pass
972 else:
973 print "Invalid parser format"
adminbae64d82013-08-01 10:50:15 -0700974 main.exit()
Jon Hall44506242015-07-29 17:40:26 -0700975 except ImportError:
Jon Hall714eeba2015-09-29 17:53:10 -0700976 print "Could not find the file " + path +\
977 " using default parser."
Jon Halld61331b2015-02-17 16:35:47 -0800978 load_defaultParser()
Jon Hall714eeba2015-09-29 17:53:10 -0700979 elif confighash['config']['parser']['file'] is None or\
980 confighash['config']['parser']['class'] is None:
Jon Halld61331b2015-02-17 16:35:47 -0800981 load_defaultParser()
adminbae64d82013-08-01 10:50:15 -0700982 else:
983 load_defaultParser()
984
985def load_defaultParser():
986 '''
Jon Hall714eeba2015-09-29 17:53:10 -0700987 It will load the default parser which is xml parser to parse the params and
988 topology file.
adminbae64d82013-08-01 10:50:15 -0700989 '''
990 moduleList = main.parserPath.split("/")
Jon Hall714eeba2015-09-29 17:53:10 -0700991 newModule = ".".join( moduleList[-2:] )
992 try:
Jon Halld61331b2015-02-17 16:35:47 -0800993 parsingClass = main.parsingClass
Jon Hall714eeba2015-09-29 17:53:10 -0700994 parsingModule = __import__( newModule,
995 globals(),
996 locals(),
997 [parsingClass],
998 -1 )
999 parsingClass = getattr( parsingModule, parsingClass )
adminbae64d82013-08-01 10:50:15 -07001000 main.parser = parsingClass()
Jon Hall714eeba2015-09-29 17:53:10 -07001001 if hasattr( main.parser, "parseParams" ) and\
1002 hasattr( main.parser, "parseTopology" ) and\
1003 hasattr( main.parser, "parse" ):
adminbae64d82013-08-01 10:50:15 -07001004 pass
1005 else:
1006 main.exit()
adminbae64d82013-08-01 10:50:15 -07001007 except ImportError:
1008 print sys.exc_info()[1]
1009
Jon Hall714eeba2015-09-29 17:53:10 -07001010def load_logger():
adminbae64d82013-08-01 10:50:15 -07001011 '''
1012 It facilitates the loading customised parser for topology and params file.
1013 It loads parser mentioned in tab named parser of teston.cfg file.
Jon Hall714eeba2015-09-29 17:53:10 -07001014 It also loads default xmlparser if no parser have specified in teston.cfg
1015 file.
adminbae64d82013-08-01 10:50:15 -07001016 '''
1017 confighash = main.configDict
Jon Hall714eeba2015-09-29 17:53:10 -07001018 if 'file' in confighash['config']['logger'] and\
1019 'class' in confighash['config']['logger']:
Jon Hall44506242015-07-29 17:40:26 -07001020 path = confighash['config']['logger']['file']
Jon Hall714eeba2015-09-29 17:53:10 -07001021 if path is not None or\
1022 confighash['config']['logger']['class'] is not None:
Jon Hall44506242015-07-29 17:40:26 -07001023 try:
1024 module = re.sub( r".py\s*$", "", path )
Jon Hall714eeba2015-09-29 17:53:10 -07001025 moduleList = module.split( "/" )
1026 newModule = ".".join( moduleList[-2:] )
Jon Hall44506242015-07-29 17:40:26 -07001027 loggerClass = confighash['config']['logger']['class']
Jon Hall714eeba2015-09-29 17:53:10 -07001028 loggerModule = __import__( newModule,
1029 globals(),
1030 locals(),
1031 [loggerClass],
1032 -1 )
1033 loggerClass = getattr( loggerModule, loggerClass )
Jon Hall44506242015-07-29 17:40:26 -07001034 main.logger = loggerClass()
Jon Hall44506242015-07-29 17:40:26 -07001035 except ImportError:
Jon Hall714eeba2015-09-29 17:53:10 -07001036 print "Could not find the file " + path +\
1037 " using default logger."
adminbae64d82013-08-01 10:50:15 -07001038 load_defaultlogger()
Jon Hall714eeba2015-09-29 17:53:10 -07001039 elif confighash['config']['parser']['file'] is None or\
1040 confighash['config']['parser']['class'] is None:
Jon Halld61331b2015-02-17 16:35:47 -08001041 load_defaultlogger()
adminbae64d82013-08-01 10:50:15 -07001042 else:
1043 load_defaultlogger()
1044
1045def load_defaultlogger():
1046 '''
Jon Hall714eeba2015-09-29 17:53:10 -07001047 It will load the default parser which is xml parser to parse the params and
1048 topology file.
adminbae64d82013-08-01 10:50:15 -07001049 '''
1050 moduleList = main.loggerPath.split("/")
Jon Hall714eeba2015-09-29 17:53:10 -07001051 newModule = ".".join( moduleList[-2:] )
1052 try:
Jon Halld61331b2015-02-17 16:35:47 -08001053 loggerClass = main.loggerClass
Jon Hall714eeba2015-09-29 17:53:10 -07001054 loggerModule = __import__( newModule,
1055 globals(),
1056 locals(),
1057 [loggerClass],
1058 -1 )
1059 loggerClass = getattr( loggerModule, loggerClass )
adminbae64d82013-08-01 10:50:15 -07001060 main.logger = loggerClass()
1061
1062 except ImportError:
1063 print sys.exc_info()[1]
Jon Halld61331b2015-02-17 16:35:47 -08001064 main.exit()
adminbae64d82013-08-01 10:50:15 -07001065
Jon Hall714eeba2015-09-29 17:53:10 -07001066def _echo( self ):
adminbae64d82013-08-01 10:50:15 -07001067 print "THIS IS ECHO"