blob: 4bbdc3cc8595b278d0ccaff40fd2488fadc9c4c8 [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'] )
adminbae64d82013-08-01 10:50:15 -0700165
Jon Hall714eeba2015-09-29 17:53:10 -0700166 driver_options['name'] = component
adminbae64d82013-08-01 10:50:15 -0700167 driverName = self.componentDictionary[component]['type']
Jon Hall714eeba2015-09-29 17:53:10 -0700168 driver_options['type'] = driverName
kelvin-onlabf70fd542015-05-07 18:41:40 -0700169
Jon Hall714eeba2015-09-29 17:53:10 -0700170 classPath = self.getDriverPath( driverName.lower() )
171 driverModule = importlib.import_module( classPath )
172 driverClass = getattr( driverModule, driverName )
adminbae64d82013-08-01 10:50:15 -0700173 driverObject = driverClass()
kelvin-onlabf70fd542015-05-07 18:41:40 -0700174
Jon Hall714eeba2015-09-29 17:53:10 -0700175 if "OCN" in self.componentDictionary[component]['host'] and\
176 main.onoscell:
Hari Krishnabe4b97b2015-07-15 12:19:43 -0700177 self.componentDictionary[component]['host'] = main.mnIP
178
Jon Hall714eeba2015-09-29 17:53:10 -0700179 user_name = self.componentDictionary[component].get( 'user',
180 getpass.getuser() )
181 ip_address = self.componentDictionary[component].get( 'host',
182 'localhost' )
183 pwd = self.componentDictionary[component].get( 'password',
184 'changeme' )
185 port = self.componentDictionary[component].get( 'port' )
186 connect_result = driverObject.connect( user_name=user_name,
187 ip_address=ip_address,
188 pwd=pwd,
189 port=port,
190 options=driver_options)
cameron@onlab.us5cc6a372015-05-11 17:18:07 -0700191
adminbae64d82013-08-01 10:50:15 -0700192 if not connect_result:
Jon Hall714eeba2015-09-29 17:53:10 -0700193 self.log.error( "Exiting from the test execution because connecting to the " +
194 component + " component failed." )
Jon Halld61331b2015-02-17 16:35:47 -0800195 self.exit()
kelvin-onlabf70fd542015-05-07 18:41:40 -0700196
Jon Hall714eeba2015-09-29 17:53:10 -0700197 vars( self )[component] = driverObject
Jon Hall0fc0d452015-07-14 09:49:58 -0700198 self.initiated = True
kelvin-onlabf70fd542015-05-07 18:41:40 -0700199
Jon Hall714eeba2015-09-29 17:53:10 -0700200 def run( self ):
adminbae64d82013-08-01 10:50:15 -0700201 '''
Jon Hall714eeba2015-09-29 17:53:10 -0700202 The Execution of the test script's cases listed in the Test params
203 file will be done here then update each test case result.
204 This method will return main.TRUE if it executed all the test cases
205 successfully, else will retun main.FALSE
adminbae64d82013-08-01 10:50:15 -0700206 '''
adminbae64d82013-08-01 10:50:15 -0700207 self.testCaseResult = {}
Jon Halla1185982014-09-15 14:55:10 -0700208 self.TOTAL_TC = 0
adminbae64d82013-08-01 10:50:15 -0700209 self.TOTAL_TC_RUN = 0
Jon Halld61331b2015-02-17 16:35:47 -0800210 self.TOTAL_TC_PLANNED = 0
adminbae64d82013-08-01 10:50:15 -0700211 self.TOTAL_TC_NORESULT = 0
212 self.TOTAL_TC_FAIL = 0
213 self.TOTAL_TC_PASS = 0
Jon Halla1185982014-09-15 14:55:10 -0700214 self.TEST_ITERATION = 0
Jon Hall714eeba2015-09-29 17:53:10 -0700215
216 # NOTE: number of main.step statements in the
217 # outer most level of the test case. used to
218 # execute code in smaller steps
219 self.stepCount = 0
kelvin-onlabf70fd542015-05-07 18:41:40 -0700220 self.CASERESULT = self.NORESULT
221
Jon Halld61331b2015-02-17 16:35:47 -0800222 import testparser
Jon Hall714eeba2015-09-29 17:53:10 -0700223 testFile = self.tests_path + "/" + self.TEST + "/" + self.TEST + ".py"
224 test = testparser.TestParser( testFile )
adminbae64d82013-08-01 10:50:15 -0700225 self.testscript = test.testscript
226 self.code = test.getStepCode()
Jon Hall714eeba2015-09-29 17:53:10 -0700227 repeat = int( self.params.get( 'repeat', 1 ) )
228 self.TOTAL_TC_PLANNED = len( self.testcases_list ) * repeat
kelvin-onlabf70fd542015-05-07 18:41:40 -0700229
adminbae64d82013-08-01 10:50:15 -0700230 result = self.TRUE
Jon Hall714eeba2015-09-29 17:53:10 -0700231 while repeat:
Jon Halla1185982014-09-15 14:55:10 -0700232 for self.CurrentTestCaseNumber in self.testcases_list:
Jon Hall714eeba2015-09-29 17:53:10 -0700233 result = self.runCase( self.CurrentTestCaseNumber )
234 repeat -= 1
adminbae64d82013-08-01 10:50:15 -0700235 return result
kelvin-onlabf70fd542015-05-07 18:41:40 -0700236
Jon Halle234cc42015-08-31 15:26:47 -0700237 def runCase( self, testCaseNumber ):
adminbae64d82013-08-01 10:50:15 -0700238 self.CurrentTestCaseNumber = testCaseNumber
kelvin-onlabf70fd542015-05-07 18:41:40 -0700239 self.CurrentTestCase = ""
Jon Hall714eeba2015-09-29 17:53:10 -0700240
241 # List of step results in a case. ANDed together to get the result
242 self.stepResultsList = []
kelvin-onlabf70fd542015-05-07 18:41:40 -0700243 self.stepName = ""
Jon Hall783bbf92015-07-23 14:33:19 -0700244 self.caseExplanation = ""
adminbae64d82013-08-01 10:50:15 -0700245 result = self.TRUE
Jon Hall714eeba2015-09-29 17:53:10 -0700246
247 # NOTE: number of main.step statements in the
248 # outer most level of the test case. used to
249 # execute code in smaller steps
250 self.stepCount = 0
251
252 # NOTE: This is the current number of main.step()'s executed
253 # in a case. Used for logging.
254 self.stepNumber = 0
adminbae64d82013-08-01 10:50:15 -0700255 self.EXPERIMENTAL_MODE = self.FALSE
256 self.addCaseHeader()
Jon Halle234cc42015-08-31 15:26:47 -0700257 self.testCaseNumber = str( testCaseNumber )
258 self.CASERESULT = self.NORESULT
adminbae64d82013-08-01 10:50:15 -0700259 stopped = False
Jon Hall5a72b712015-09-28 12:20:59 -0700260 try:
261 self.code[self.testCaseNumber]
Jon Halld61331b2015-02-17 16:35:47 -0800262 except KeyError:
Jon Halle234cc42015-08-31 15:26:47 -0700263 self.log.error( "There is no Test-Case " + self.testCaseNumber )
Jon Hallfebb1c72015-03-05 13:30:09 -0800264 return self.FALSE
adminbae64d82013-08-01 10:50:15 -0700265 self.stepCount = 0
Jon Hall714eeba2015-09-29 17:53:10 -0700266 while self.stepCount < len( self.code[self.testCaseNumber].keys() ):
267 result = self.runStep( self.code, self.testCaseNumber )
Jon Hallfebb1c72015-03-05 13:30:09 -0800268 if result == self.FALSE:
adminbae64d82013-08-01 10:50:15 -0700269 break
Jon Hallfebb1c72015-03-05 13:30:09 -0800270 elif result == self.TRUE:
adminbae64d82013-08-01 10:50:15 -0700271 continue
Jon Hall5a72b712015-09-28 12:20:59 -0700272 # stepResults format: ( stepNo[], stepName[], stepResult[], onFail[] )
273 stepResults = self.stepResultsList
Jon Halle234cc42015-08-31 15:26:47 -0700274 if not stopped:
275 if self.CASERESULT == self.TRUE or self.CASERESULT == self.FALSE:
Jon Hall714eeba2015-09-29 17:53:10 -0700276 # Result was already explitily set somewhere else like
277 # in skipCase()
Jon Halle234cc42015-08-31 15:26:47 -0700278 pass
Jon Hall5a72b712015-09-28 12:20:59 -0700279 elif all( self.TRUE == i for i in stepResults ):
kelvin-onlabf70fd542015-05-07 18:41:40 -0700280 # ALL PASSED
281 self.CASERESULT = self.TRUE
Jon Hall5a72b712015-09-28 12:20:59 -0700282 elif self.FALSE in stepResults:
kelvin-onlabf70fd542015-05-07 18:41:40 -0700283 # AT LEAST ONE FAILED
284 self.CASERESULT = self.FALSE
Jon Hall5a72b712015-09-28 12:20:59 -0700285 elif self.TRUE in stepResults:
kelvin-onlabf70fd542015-05-07 18:41:40 -0700286 # AT LEAST ONE PASSED
287 self.CASERESULT = self.TRUE
288 else:
289 self.CASERESULT = self.NORESULT
Jon Hall714eeba2015-09-29 17:53:10 -0700290 self.testCaseResult[str( self.CurrentTestCaseNumber )] = self.CASERESULT
291 self.logger.updateCaseResults( self )
Jon Hall783bbf92015-07-23 14:33:19 -0700292 self.log.wiki( "<p>" + self.caseExplanation + "</p>" )
293 self.log.summary( self.caseExplanation )
kelvin-onlabf70fd542015-05-07 18:41:40 -0700294 self.log.wiki( "<ul>" )
acsmarse2d1ed12015-10-05 13:51:17 -0700295 subcaseMessage = False
kelvin-onlabf70fd542015-05-07 18:41:40 -0700296 for line in self.stepCache.splitlines():
acsmarse2d1ed12015-10-05 13:51:17 -0700297 if re.search( "[0-9]\.[0-9]", line ): # Step
298 if subcaseMessage: # End of Failure Message Printout
299 self.log.wiki( "</ul>\n" )
300 subcaseMessage = False
301 if re.search( " - PASS$", line ):
302 self.log.wiki( "<li>" + line + " <ac:emoticon ac:name=\"tick\" /></li>\n" )
303 elif re.search( " - FAIL$", line ):
304 self.log.wiki( "<li>" + line + " <ac:emoticon ac:name=\"cross\" /></li>\n" )
305 elif re.search( " - No Result$", line ):
306 self.log.wiki( "<li>" + line + " <ac:emoticon ac:name=\"warning\" /></li>\n" )
307 else: # Substep
308 if not subcaseMessage: # Open Failure Message Printout
309 self.log.wiki( "<ul><li>" + line + "</li>\n" )
310 subcaseMessage = True
311 else: # Add to Failure Message Printout
312 self.log.wiki( "<li>" + line + "</li>\n" )
acsmars27e62dd2015-10-06 11:35:47 -0700313 if subcaseMessage: # End of Failure Message Printout for last item
314 self.log.wiki( "</ul>\n" )
kelvin-onlabf70fd542015-05-07 18:41:40 -0700315 self.log.wiki( "</ul>" )
316 self.log.summary( self.stepCache )
317 self.stepCache = ""
adminbae64d82013-08-01 10:50:15 -0700318 return result
kelvin-onlabf70fd542015-05-07 18:41:40 -0700319
Jon Hall714eeba2015-09-29 17:53:10 -0700320 def runStep( self, code, testCaseNumber ):
adminbae64d82013-08-01 10:50:15 -0700321 if not cli.pause:
Jon Hall5a72b712015-09-28 12:20:59 -0700322 try:
323 step = self.stepCount
324 # stepResults format: ( stepNo, stepName, stepResult, onFail )
325 # NOTE: This is needed to catch results of main.step()'s
326 # called inside functions or loops
327 self.stepResults = ( [], [], [], [] )
adminbae64d82013-08-01 10:50:15 -0700328 exec code[testCaseNumber][step] in module.__dict__
329 self.stepCount = self.stepCount + 1
Jon Hall5a72b712015-09-28 12:20:59 -0700330
331 # Iterate through each of the steps and print them
332 for index in range( len( self.stepResults[0] ) ):
Jon Hall714eeba2015-09-29 17:53:10 -0700333 # stepResults = ( stepNo, stepName, stepResult, onFail )
Jon Hall5a72b712015-09-28 12:20:59 -0700334 stepNo = self.stepResults[0][ index ]
335 stepName = self.stepResults[1][ index ]
336 stepResult = self.stepResults[2][ index ]
337 onFail = self.stepResults[3][ index ]
338 self.stepCache += "\t" + str( testCaseNumber ) + "."
339 self.stepCache += str( stepNo ) + " "
340 self.stepCache += stepName + " - "
341 if stepResult == self.TRUE:
kelvin-onlabf70fd542015-05-07 18:41:40 -0700342 self.stepCache += "PASS\n"
Jon Hall5a72b712015-09-28 12:20:59 -0700343 elif stepResult == self.FALSE:
kelvin-onlabf70fd542015-05-07 18:41:40 -0700344 self.stepCache += "FAIL\n"
Jon Hall5a72b712015-09-28 12:20:59 -0700345 self.stepCache += "\t\t" + onFail + "\n"
kelvin-onlabf70fd542015-05-07 18:41:40 -0700346 else:
347 self.stepCache += "No Result\n"
Jon Hall714eeba2015-09-29 17:53:10 -0700348 self.stepResultsList.append( stepResult )
Jon Halle234cc42015-08-31 15:26:47 -0700349 except StopIteration: # Raised in self.skipCase()
350 self.log.warn( "Skipping the rest of CASE" +
351 str( testCaseNumber ) )
Jon Hall714eeba2015-09-29 17:53:10 -0700352 self.stepResultsList.append( self.STEPRESULT )
Jon Halle234cc42015-08-31 15:26:47 -0700353 self.stepCache += "\t\t" + self.onFailMsg + "\n"
354 self.stepCount = self.stepCount + 1
355 return self.FALSE
Jon Hallc1606352015-10-06 14:51:36 -0700356 except StandardError as e:
357 try:
358 stepNo = self.stepResults[0][ self.stepNumber - 1 ]
359 except IndexError:
360 stepNo = "<IndexError>"
361 main.log.warn( "Error trying to get step number. " +
362 "It is likely between step " +
363 str( self.stepNumber ) + " and step" +
364 str( self.stepNumber + 1 ) )
365 try:
366 stepName = self.stepResults[1][ self.stepNumber - 1 ]
367 except IndexError:
368 stepName = "<IndexError>"
369 self.log.error( "\nException in the following section of" +
370 " code: " + str( testCaseNumber ) + "." +
371 str( stepNo ) + ": " + stepName )
372 self.log.error( e )
adminbae64d82013-08-01 10:50:15 -0700373 self.stepCount = self.stepCount + 1
Jon Hall714eeba2015-09-29 17:53:10 -0700374 self.logger.updateCaseResults( self )
375 # WIKI results
kelvin-onlabf70fd542015-05-07 18:41:40 -0700376 self.log.wiki( "<ul>" )
377 for line in self.stepCache.splitlines():
378 if re.search( " - PASS$", line ):
379 self.log.wiki( "<li>" + line + " <ac:emoticon ac:name=\"tick\" /></li>\n" )
380 elif re.search( " - FAIL$", line ):
381 self.log.wiki( "<li>" + line + " <ac:emoticon ac:name=\"cross\" /></li>\n" )
382 elif re.search( " - No Result$", line ):
383 self.log.wiki( "<li>" + line + " <ac:emoticon ac:name=\"warning\" /></li>\n" )
Jon Hall90627612015-06-09 14:57:02 -0700384 else: # Should only be on fail message
385 self.log.wiki( "<ul><li>" + line + "</li></ul>\n" )
kelvin-onlabf70fd542015-05-07 18:41:40 -0700386 self.log.wiki( "</ul>" )
Jon Hall714eeba2015-09-29 17:53:10 -0700387 # summary results
kelvin-onlabf70fd542015-05-07 18:41:40 -0700388 self.log.summary( self.stepCache )
389 self.stepCache = ""
shahshreya957feaa2015-03-23 16:08:29 -0700390 self.cleanup()
Jon Hall00539b12015-04-03 13:55:46 -0700391 self.exit()
Jon Halle234cc42015-08-31 15:26:47 -0700392 return self.TRUE
adminbae64d82013-08-01 10:50:15 -0700393 if cli.stop:
394 cli.stop = False
adminbae64d82013-08-01 10:50:15 -0700395 self.TOTAL_TC_NORESULT = self.TOTAL_TC_NORESULT + 1
Jon Hall714eeba2015-09-29 17:53:10 -0700396 self.testCaseResult[str( self.CurrentTestCaseNumber )] = "Stopped"
397 self.logger.updateCaseResults( self )
adminbae64d82013-08-01 10:50:15 -0700398 result = self.cleanup()
Jon Halle234cc42015-08-31 15:26:47 -0700399 return self.FALSE
400
401 def skipCase( self, result="DEFAULT", msg=None ):
402 """
403 Will skip the rest of the code in a test case. The case results will be
404 determined as normal based on completed assertions unless the result
405 argument is given.
406
407 Optional Arguments:
408 result: Case insensite string. Can be 'PASS' or 'FAIL' and will set
409 the case result accordingly.
410 msg: Message to be printed when the case is skipped in the reports.
411 """
412 result = result.upper().strip()
413 if result == "PASS":
414 self.CASERESULT = self.TRUE
415 elif result == "FAIL":
416 self.CASERESULT = self.FALSE
417 self.onFailMsg = "Skipping the rest of this case. "
418 if msg:
419 self.onFailMsg += str( msg )
420 raise StopIteration
kelvin-onlabf70fd542015-05-07 18:41:40 -0700421
Jon Hall714eeba2015-09-29 17:53:10 -0700422 def addCaseHeader( self ):
423 caseHeader = "\n" + "*" * 30 + "\n Result summary for Testcase" +\
424 str( self.CurrentTestCaseNumber ) + "\n" + "*" * 30 + "\n"
425 self.log.exact( caseHeader )
426 caseHeader = "\n" + "*" * 40 + "\nStart of Test Case" +\
427 str( self.CurrentTestCaseNumber ) + " : "
adminbae64d82013-08-01 10:50:15 -0700428 for driver in self.componentDictionary.keys():
Jon Hall714eeba2015-09-29 17:53:10 -0700429 vars( self )[driver + 'log'].info( caseHeader )
kelvin-onlabf70fd542015-05-07 18:41:40 -0700430
Jon Hall714eeba2015-09-29 17:53:10 -0700431 def addCaseFooter( self ):
Jon Hall5a72b712015-09-28 12:20:59 -0700432 stepNo = self.stepResults[0][-2]
Jon Hall714eeba2015-09-29 17:53:10 -0700433 if stepNo > 0:
434 previousStep = " " + str( self.CurrentTestCaseNumber ) + "." +\
435 str( stepNo ) + ": " + str( self.stepName )
436 stepHeader = "\n" + "*" * 40 + "\nEnd of Step " + previousStep +\
437 "\n" + "*" * 40 + "\n"
kelvin-onlabf70fd542015-05-07 18:41:40 -0700438
Jon Hall714eeba2015-09-29 17:53:10 -0700439 caseFooter = "\n" + "*" * 40 + "\nEnd of Test case " +\
440 str( self.CurrentTestCaseNumber ) + "\n" + "*" * 40 + "\n"
kelvin-onlabf70fd542015-05-07 18:41:40 -0700441
adminbae64d82013-08-01 10:50:15 -0700442 for driver in self.driversList:
Jon Hall714eeba2015-09-29 17:53:10 -0700443 vars( self )[driver].write( stepHeader + "\n" + caseFooter )
adminbae64d82013-08-01 10:50:15 -0700444
Jon Hall714eeba2015-09-29 17:53:10 -0700445 def cleanup( self ):
adminbae64d82013-08-01 10:50:15 -0700446 '''
Jon Hall5b586732015-06-11 11:39:39 -0700447 Print a summary of the current test's results then attempt to release
448 all the component handles and the close opened file handles.
adminbae64d82013-08-01 10:50:15 -0700449
Jon Hall5b586732015-06-11 11:39:39 -0700450 This function shouldbe threadsafe such that cleanup will only be
451 executed once per test.
452
453 This will return TRUE if all the component handles and log handles
454 closed properly, else return FALSE.
adminbae64d82013-08-01 10:50:15 -0700455 '''
456 result = self.TRUE
Jon Hall5b586732015-06-11 11:39:39 -0700457 lock = self.cleanupLock
458 if lock.acquire( False ):
459 try:
460 if self.cleanupFlag is False: # First thread to run this
461 self.cleanupFlag = True
Jon Hall0fc0d452015-07-14 09:49:58 -0700462 if self.initiated:
Jon Hall714eeba2015-09-29 17:53:10 -0700463 self.logger.testSummary( self )
Jon Hall5b586732015-06-11 11:39:39 -0700464 for component in self.componentDictionary.keys():
Jon Hall714eeba2015-09-29 17:53:10 -0700465 try:
466 tempObject = vars( self )[component]
467 print "Disconnecting from " + str( tempObject.name ) +\
468 ": " + str( tempObject.__class__)
Jon Hall5b586732015-06-11 11:39:39 -0700469 tempObject.disconnect()
Jon Hall1306a562015-09-04 11:21:24 -0700470 except KeyboardInterrupt:
471 pass
472 except KeyError:
473 # Component not created yet
474 self.log.warn( "Could not find the component " +
475 str( component ) )
476 except StandardError:
Jon Hall5b586732015-06-11 11:39:39 -0700477 self.log.exception( "Exception while disconnecting from " +
478 str( component ) )
479 result = self.FALSE
480 # Closing all the driver's session files
481 for driver in self.componentDictionary.keys():
482 try:
Jon Hall714eeba2015-09-29 17:53:10 -0700483 vars( self )[driver].close_log_handles()
Jon Hall1306a562015-09-04 11:21:24 -0700484 except KeyboardInterrupt:
485 pass
486 except KeyError:
487 # Component not created yet
488 self.log.warn( "Could not find the component " +
489 str( driver ) + " while trying to" +
490 " close log file" )
491 except StandardError:
Jon Hall5b586732015-06-11 11:39:39 -0700492 self.log.exception( "Exception while closing log files for " +
493 str( driver ) )
494 result = self.FALSE
495 else:
496 pass # Someone else already ran through this function
497 finally:
498 lock.release()
499 else: # Someone already has a lock
500 # NOTE: This could cause problems if we don't release the lock
501 # correctly
502 lock.acquire() # Wait for the other thread to finish
503 # NOTE: If we don't wait, exit could be called while the thread
504 # with the lock is still cleaning up
505 lock.release()
adminbae64d82013-08-01 10:50:15 -0700506 return result
Jon Halld61331b2015-02-17 16:35:47 -0800507
Jon Hall714eeba2015-09-29 17:53:10 -0700508 def pause( self ):
adminbae64d82013-08-01 10:50:15 -0700509 '''
Jon Hall714eeba2015-09-29 17:53:10 -0700510 This function will pause the test's execution, and will continue after
511 user provide 'resume' command.
adminbae64d82013-08-01 10:50:15 -0700512 '''
513 __builtin__.testthread.pause()
kelvin-onlabf70fd542015-05-07 18:41:40 -0700514
Jon Hall714eeba2015-09-29 17:53:10 -0700515 def onfail( self, *components ):
adminbae64d82013-08-01 10:50:15 -0700516 '''
kelvin-onlabf70fd542015-05-07 18:41:40 -0700517 When test step failed, calling all the components onfail.
adminbae64d82013-08-01 10:50:15 -0700518 '''
adminbae64d82013-08-01 10:50:15 -0700519 if not components:
Jon Hall714eeba2015-09-29 17:53:10 -0700520 try:
adminbae64d82013-08-01 10:50:15 -0700521 for component in self.componentDictionary.keys():
Jon Hall714eeba2015-09-29 17:53:10 -0700522 tempObject = vars( self )[component]
adminbae64d82013-08-01 10:50:15 -0700523 result = tempObject.onfail()
Jon Hall1306a562015-09-04 11:21:24 -0700524 except StandardError as e:
Jon Hall714eeba2015-09-29 17:53:10 -0700525 print str( e )
adminbae64d82013-08-01 10:50:15 -0700526 result = self.FALSE
adminbae64d82013-08-01 10:50:15 -0700527 else:
Jon Hall714eeba2015-09-29 17:53:10 -0700528 try:
adminbae64d82013-08-01 10:50:15 -0700529 for component in components:
Jon Hall714eeba2015-09-29 17:53:10 -0700530 tempObject = vars( self )[component]
adminbae64d82013-08-01 10:50:15 -0700531 result = tempObject.onfail()
Jon Hall1306a562015-09-04 11:21:24 -0700532 except StandardError as e:
Jon Hall714eeba2015-09-29 17:53:10 -0700533 print str( e )
adminbae64d82013-08-01 10:50:15 -0700534 result = self.FALSE
kelvin-onlabf70fd542015-05-07 18:41:40 -0700535
Jon Hall714eeba2015-09-29 17:53:10 -0700536 def getDriverPath( self, driverName ):
adminbae64d82013-08-01 10:50:15 -0700537 '''
Jon Hall714eeba2015-09-29 17:53:10 -0700538 Based on the component 'type' specified in the params , this method
539 will find the absolute path, by recursively searching the name of
540 the component.
541
542 NOTE: This function requires the linux 'find' command.
adminbae64d82013-08-01 10:50:15 -0700543 '''
544 import commands
545
Jon Hall714eeba2015-09-29 17:53:10 -0700546 cmd = "find " + drivers_path + " -name " + driverName + ".py"
547 result = commands.getoutput( cmd )
kelvin-onlabf70fd542015-05-07 18:41:40 -0700548
Jon Hall714eeba2015-09-29 17:53:10 -0700549 result_array = str( result ).split( '\n' )
adminbae64d82013-08-01 10:50:15 -0700550 result_count = 0
kelvin-onlabf70fd542015-05-07 18:41:40 -0700551
adminbae64d82013-08-01 10:50:15 -0700552 for drivers_list in result_array:
Jon Hall714eeba2015-09-29 17:53:10 -0700553 result_count = result_count + 1
554 if result_count > 1:
555 print "Found " + driverName + " " + str( result_count ) + " times:"
556 print str( result_array )
adminbae64d82013-08-01 10:50:15 -0700557 self.exit()
kelvin-onlabf70fd542015-05-07 18:41:40 -0700558
Jon Hall714eeba2015-09-29 17:53:10 -0700559 result = re.sub( "(.*)drivers", "", result )
560 result = re.sub( "\/\/", "/", result )
561 result = re.sub( "\.py", "", result )
562 result = re.sub( "\.pyc", "", result )
563 result = re.sub( "\/", ".", result )
564 result = "drivers" + result
adminbae64d82013-08-01 10:50:15 -0700565 return result
adminbae64d82013-08-01 10:50:15 -0700566
Jon Hall714eeba2015-09-29 17:53:10 -0700567 def step( self, stepDesc ):
adminbae64d82013-08-01 10:50:15 -0700568 '''
569 The step information of the test-case will append to the logs.
570 '''
Jon Hall714eeba2015-09-29 17:53:10 -0700571 previousStep = " " + str( self.CurrentTestCaseNumber ) + "." +\
572 str( self.stepNumber ) + ": " + str( self.stepName )
adminbae64d82013-08-01 10:50:15 -0700573 self.stepName = stepDesc
Jon Hall5a72b712015-09-28 12:20:59 -0700574 self.stepNumber += 1
575 self.stepResults[0].append( self.stepNumber )
576 self.stepResults[1].append( stepDesc )
577 self.stepResults[2].append( self.NORESULT )
578 self.stepResults[3].append( "No on fail message given" )
adminbae64d82013-08-01 10:50:15 -0700579
Jon Hall714eeba2015-09-29 17:53:10 -0700580 stepName = " " + str( self.CurrentTestCaseNumber ) + "." +\
581 str( self.stepNumber ) + ": " + str( stepDesc )
adminbae64d82013-08-01 10:50:15 -0700582 self.log.step(stepName)
583 stepHeader = ""
Jon Hall714eeba2015-09-29 17:53:10 -0700584 line = "\n" + "-" * 45 + "\n"
585 if self.stepNumber > 1:
586 stepHeader = line + "End of Step " + previousStep + line
587 stepHeader += line + "Start of Step" + stepName + line
adminbae64d82013-08-01 10:50:15 -0700588 for driver in self.componentDictionary.keys():
Jon Hall714eeba2015-09-29 17:53:10 -0700589 vars( self )[driver + 'log'].info( stepHeader )
kelvin-onlabf70fd542015-05-07 18:41:40 -0700590
Jon Hall714eeba2015-09-29 17:53:10 -0700591 def case( self, testCaseName ):
adminbae64d82013-08-01 10:50:15 -0700592 '''
593 Test's each test-case information will append to the logs.
594 '''
Jon Halld61331b2015-02-17 16:35:47 -0800595 self.CurrentTestCase = testCaseName
Jon Hall714eeba2015-09-29 17:53:10 -0700596 testCaseName = " " + str( testCaseName )
597 self.log.case( testCaseName )
598 caseHeader = testCaseName + "\n" + "*" * 40 + "\n"
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( caseHeader )
kelvin-onlabf70fd542015-05-07 18:41:40 -0700601
Jon Hall714eeba2015-09-29 17:53:10 -0700602 def testDesc( self, description ):
adminbae64d82013-08-01 10:50:15 -0700603 '''
604 Test description will append to the logs.
605 '''
Jon Hall714eeba2015-09-29 17:53:10 -0700606 description = "Test Description : " + str( description )
607 self.log.info( description )
kelvin-onlabf70fd542015-05-07 18:41:40 -0700608
Jon Hall714eeba2015-09-29 17:53:10 -0700609 def _getTest( self ):
adminbae64d82013-08-01 10:50:15 -0700610 '''
Jon Hall714eeba2015-09-29 17:53:10 -0700611 This method will parse the test script to find required test
612 information.
adminbae64d82013-08-01 10:50:15 -0700613 '''
Jon Hall714eeba2015-09-29 17:53:10 -0700614 testFile = self.tests_path + "/" + self.TEST + "/" + self.TEST + ".py"
615 testFileHandler = open( testFile, 'r' )
adminbae64d82013-08-01 10:50:15 -0700616 testFileList = testFileHandler.readlines()
617 testFileHandler.close()
adminbae64d82013-08-01 10:50:15 -0700618 counter = 0
Jon Hall714eeba2015-09-29 17:53:10 -0700619 for index in range( len( testFileList ) ):
620 lineMatch = re.match( '\s+def CASE(\d+)(.*):',
621 testFileList[index],
622 0 )
adminbae64d82013-08-01 10:50:15 -0700623 if lineMatch:
Jon Hall714eeba2015-09-29 17:53:10 -0700624 counter = counter + 1
625 self.TC_PLANNED = len( self.testcases_list )
kelvin-onlabf70fd542015-05-07 18:41:40 -0700626
Jon Hall714eeba2015-09-29 17:53:10 -0700627 def response_parser( self, response, return_format ):
adminbae64d82013-08-01 10:50:15 -0700628 ''' It will load the default response parser '''
629 response_dict = {}
Jon Hall714eeba2015-09-29 17:53:10 -0700630 response_dict = self.response_to_dict( response, return_format )
631 return_format_string = self.dict_to_return_format( response,
632 return_format,
633 response_dict )
adminbae64d82013-08-01 10:50:15 -0700634 return return_format_string
kelvin-onlabf70fd542015-05-07 18:41:40 -0700635
Jon Hall714eeba2015-09-29 17:53:10 -0700636 def response_to_dict( self, response, return_format ):
adminbae64d82013-08-01 10:50:15 -0700637 response_dict = {}
Jon Hall714eeba2015-09-29 17:53:10 -0700638 json_match = re.search( '^\s*{', response )
639 xml_match = re.search( '^\s*\<', response )
640 ini_match = re.search( '^\s*\[', response )
641 if json_match:
642 self.log.info( "Response is in 'JSON' format, converting to '" +
643 return_format + "' format" )
Jon Halld61331b2015-02-17 16:35:47 -0800644 # Formatting the json string
Jon Hall714eeba2015-09-29 17:53:10 -0700645 response = re.sub( r"{\s*'?(\w)", r'{"\1', response )
646 response = re.sub( r",\s*'?(\w)", r',"\1', response )
647 response = re.sub( r"(\w)'?\s*:", r'\1":', response )
648 response = re.sub( r":\s*'(\w)'\s*([,}])", r':"\1"\2', response )
649 try:
adminbae64d82013-08-01 10:50:15 -0700650 import json
Jon Hall714eeba2015-09-29 17:53:10 -0700651 response_dict = json.loads( response )
Jon Hall1306a562015-09-04 11:21:24 -0700652 except StandardError:
Jon Hall2a5002c2015-08-21 16:49:11 -0700653 self.log.exception( "Json Parser is unable to parse the string" )
adminbae64d82013-08-01 10:50:15 -0700654 return response_dict
Jon Hall714eeba2015-09-29 17:53:10 -0700655 elif ini_match:
656 self.log.info( "Response is in 'INI' format, converting to '" +
657 return_format + "' format" )
adminbae64d82013-08-01 10:50:15 -0700658 from configobj import ConfigObj
Jon Hall714eeba2015-09-29 17:53:10 -0700659 response_file = open( "respnse_file.temp", 'w' )
660 response_file.write( response )
Jon Halld61331b2015-02-17 16:35:47 -0800661 response_file.close()
Jon Hall714eeba2015-09-29 17:53:10 -0700662 response_dict = ConfigObj( "respnse_file.temp" )
adminbae64d82013-08-01 10:50:15 -0700663 return response_dict
Jon Hall714eeba2015-09-29 17:53:10 -0700664 elif xml_match:
665 self.log.info( "Response is in 'XML' format, converting to '" +
666 return_format + "' format" )
667 try:
668 response_dict = xmldict.xml_to_dict( "<response> " +
669 str( response ) +
670 " </response>" )
Jon Hall1306a562015-09-04 11:21:24 -0700671 except StandardError:
672 self.log.exception()
adminbae64d82013-08-01 10:50:15 -0700673 return response_dict
kelvin-onlabf70fd542015-05-07 18:41:40 -0700674
Jon Hall714eeba2015-09-29 17:53:10 -0700675 def dict_to_return_format( self, response, return_format, response_dict ):
676 if return_format == 'table':
adminbae64d82013-08-01 10:50:15 -0700677 ''' Will return in table format'''
678 to_do = "Call the table output formatter"
679 global response_table
680 response_table = '\n'
Jon Hall714eeba2015-09-29 17:53:10 -0700681 response_table = response_table + '\t'.join( response_dict ) + "\n"
kelvin-onlabf70fd542015-05-07 18:41:40 -0700682
Jon Hall714eeba2015-09-29 17:53:10 -0700683 def get_table( value_to_convert ):
684 ''' This will parse the dictionary recusrsively and print as
685 table format'''
adminbae64d82013-08-01 10:50:15 -0700686 table_data = ""
Jon Hall714eeba2015-09-29 17:53:10 -0700687 if isinstance( value_to_convert, dict ):
688 table_data = table_data + '\t'.join( value_to_convert ) +\
689 "\n"
690 for temp_val in value_to_convert.values():
691 table_data = table_data + get_table( temp_val )
692 else:
693 table_data = table_data + str( value_to_convert ) + "\t"
Jon Halld61331b2015-02-17 16:35:47 -0800694 return table_data
kelvin-onlabf70fd542015-05-07 18:41:40 -0700695
Jon Hall714eeba2015-09-29 17:53:10 -0700696 for value in response_dict.values():
697 response_table = response_table + get_table( value )
adminbae64d82013-08-01 10:50:15 -0700698 return response_table
kelvin-onlabf70fd542015-05-07 18:41:40 -0700699
Jon Hall714eeba2015-09-29 17:53:10 -0700700 elif return_format == 'config':
adminbae64d82013-08-01 10:50:15 -0700701 ''' Will return in config format'''
702 to_do = 'Call dict to config coverter'
Jon Hall714eeba2015-09-29 17:53:10 -0700703 response_string = str( response_dict )
adminbae64d82013-08-01 10:50:15 -0700704 print response_string
Jon Hall714eeba2015-09-29 17:53:10 -0700705 response_config = re.sub( ",", "\n\t", response_string )
706 response_config = re.sub( "u\'", "\'", response_config )
707 response_config = re.sub( "{", "", response_config )
708 response_config = re.sub( "}", "\n", response_config )
709 response_config = re.sub( ":", " =", response_config )
710 return "[response]\n\t " + response_config
adminbae64d82013-08-01 10:50:15 -0700711 elif return_format == 'xml':
712 ''' Will return in xml format'''
Jon Hall714eeba2015-09-29 17:53:10 -0700713 response_xml = xmldict.dict_to_xml( response_dict )
714 response_xml = re.sub( ">\s*<", ">\n<", response_xml )
715 return "\n" + response_xml
adminbae64d82013-08-01 10:50:15 -0700716 elif return_format == 'json':
717 ''' Will return in json format'''
718 to_do = 'Call dict to xml coverter'
719 import json
Jon Hall714eeba2015-09-29 17:53:10 -0700720 response_json = json.dumps( response_dict )
adminbae64d82013-08-01 10:50:15 -0700721 return response_json
kelvin-onlabf70fd542015-05-07 18:41:40 -0700722
Jon Hall714eeba2015-09-29 17:53:10 -0700723 def get_random( self ):
adminbae64d82013-08-01 10:50:15 -0700724 self.random_order = self.random_order + 1
725 return self.random_order
kelvin-onlabf70fd542015-05-07 18:41:40 -0700726
Jon Hall714eeba2015-09-29 17:53:10 -0700727 def exit( self ):
adminbae64d82013-08-01 10:50:15 -0700728 __builtin__.testthread = None
Jon Hall5b586732015-06-11 11:39:39 -0700729 for thread in threading.enumerate():
730 if thread.isAlive():
731 try:
732 thread._Thread__stop()
733 except:
Jon Hall1306a562015-09-04 11:21:24 -0700734 # NOTE: We should catch any exceptions while trying to
735 # close the thread so that we can try to close the other
736 # threads as well
Jon Hall714eeba2015-09-29 17:53:10 -0700737 print str( thread.getName() ) +\
738 ' could not be terminated'
adminbae64d82013-08-01 10:50:15 -0700739 sys.exit()
740
Jon Hallcd3d2a32015-10-01 11:07:28 -0700741 def stop( self, email=False ):
742 """
743 Stop the test until Ctrl-D is entered.
744 Ctrl-C will kill the test
Jon Hall25079782015-10-13 13:54:39 -0700745
746 Optional arguments:
747 email can either be a bool, or you can specify the email address
748 to send the email to
Jon Hallcd3d2a32015-10-01 11:07:28 -0700749 """
750 try:
751 if email:
Jon Hall25079782015-10-13 13:54:39 -0700752 if '@' in email:
753 main.mail = email
754 utilities.send_warning_email()
Jon Hallcd3d2a32015-10-01 11:07:28 -0700755 self.log.error( "Test execution suspended. Press Ctrl-D to "
756 "resume or Ctrl-C to exit the test" )
757 # NOTE: Ctrl-D needs to be entered on a new line
758 while True:
759 # TODO: we could give the user an interactive prompt where
760 # they could call functions
761 raw_input()
762 except EOFError:
763 return
764 # Pass all other exceptions up to caller
765
766
Jon Hall714eeba2015-09-29 17:53:10 -0700767def verifyOptions( options ):
adminbae64d82013-08-01 10:50:15 -0700768 '''
Jon Hall714eeba2015-09-29 17:53:10 -0700769 This will verify the command line options and set to default values,
770 if any option not given in command line.
adminbae64d82013-08-01 10:50:15 -0700771 '''
Jon Hall714eeba2015-09-29 17:53:10 -0700772 verifyTest( options )
773 verifyExample( options )
774 verifyTestScript( options )
adminbae64d82013-08-01 10:50:15 -0700775 verifyParams()
Jon Hall714eeba2015-09-29 17:53:10 -0700776 verifyLogdir( options )
777 verifyMail( options )
778 verifyTestCases( options )
779 verifyOnosCell( options )
adminbae64d82013-08-01 10:50:15 -0700780
Jon Hall714eeba2015-09-29 17:53:10 -0700781def verifyTest( options ):
Jon Hall44506242015-07-29 17:40:26 -0700782 try:
783 if options.testname:
784 main.TEST = options.testname
Jon Hall714eeba2015-09-29 17:53:10 -0700785 main.classPath = "tests." + main.TEST + "." + main.TEST
Jon Hall44506242015-07-29 17:40:26 -0700786 main.tests_path = tests_path
787 elif options.example:
788 main.TEST = options.example
Jon Hall714eeba2015-09-29 17:53:10 -0700789 main.tests_path = path + "/examples/"
790 main.classPath = "examples." + main.TEST + "." + main.TEST
Jon Hall44506242015-07-29 17:40:26 -0700791 except AttributeError:
adminbae64d82013-08-01 10:50:15 -0700792 print "Test or Example not specified please specify the --test <test name > or --example <example name>"
Jon Hall5b586732015-06-11 11:39:39 -0700793 main.exit()
adminbae64d82013-08-01 10:50:15 -0700794
Jon Hall714eeba2015-09-29 17:53:10 -0700795def verifyExample( options ):
adminbae64d82013-08-01 10:50:15 -0700796 if options.example:
Jon Hall714eeba2015-09-29 17:53:10 -0700797 main.testDir = path + '/examples/'
798 main.tests_path = path + "/examples/"
799 main.classPath = "examples." + main.TEST + "." + main.TEST
kelvin-onlabf70fd542015-05-07 18:41:40 -0700800
Jon Hall714eeba2015-09-29 17:53:10 -0700801def verifyLogdir( options ):
Jon Hall88e498c2015-03-06 09:54:35 -0800802 # Verifying Log directory option
adminbae64d82013-08-01 10:50:15 -0700803 if options.logdir:
804 main.logdir = options.logdir
Jon Hall714eeba2015-09-29 17:53:10 -0700805 else:
Jon Halld61331b2015-02-17 16:35:47 -0800806 main.logdir = main.FALSE
kelvin-onlabf70fd542015-05-07 18:41:40 -0700807
Jon Hall714eeba2015-09-29 17:53:10 -0700808def verifyMail( options ):
Jon Hall25079782015-10-13 13:54:39 -0700809 # Mail-To: field
810 if options.mail: # Test run specific
adminbae64d82013-08-01 10:50:15 -0700811 main.mail = options.mail
Jon Hall25079782015-10-13 13:54:39 -0700812 elif main.params.get('mail'): # Test suite specific
813 main.mail = main.params.get( 'mail' )
814 else: # TestON specific
815 main.mail = main.config['config'].get( 'mail_to' )
816 # Mail-From: field
817 main.sender = main.config['config'].get( 'mail_from' )
818 # Mail smtp server
819 main.smtp = main.config['config'].get( 'mail_server' )
820 # Mail-From account password
821 main.senderPwd = main.config['config'].get( 'mail_pass' )
822
adminbae64d82013-08-01 10:50:15 -0700823
Jon Hall714eeba2015-09-29 17:53:10 -0700824def verifyTestCases( options ):
Jon Hall88e498c2015-03-06 09:54:35 -0800825 # Getting Test cases list
adminbae64d82013-08-01 10:50:15 -0700826 if options.testcases:
Jon Hallfebb1c72015-03-05 13:30:09 -0800827 testcases_list = options.testcases
Jon Hall88e498c2015-03-06 09:54:35 -0800828 # sys.exit()
Jon Hall714eeba2015-09-29 17:53:10 -0700829 testcases_list = re.sub( "(\[|\])", "", options.testcases )
830 main.testcases_list = eval( testcases_list + "," )
831 else:
adminbae64d82013-08-01 10:50:15 -0700832 if 'testcases' in main.params.keys():
Jon Hall714eeba2015-09-29 17:53:10 -0700833 temp = eval( main.params['testcases'] + "," )
834 list1 = []
835 if isinstance( temp[0], list ):
Jon Hallfebb1c72015-03-05 13:30:09 -0800836 for test in temp:
837 for testcase in test:
Jon Hall714eeba2015-09-29 17:53:10 -0700838 if isinstance( testcase, int ):
839 testcase = [testcase]
840 list1.extend( testcase )
841 else:
842 temp = list( temp )
Jon Hallfebb1c72015-03-05 13:30:09 -0800843 for testcase in temp:
Jon Hall714eeba2015-09-29 17:53:10 -0700844 if isinstance( testcase, int ):
845 testcase = [testcase]
846 list1.extend( testcase )
847 main.testcases_list = list1
848 else:
849 print "Testcases not specifed in params, please provide in " +\
850 "params file or 'testcases' commandline argument"
Jon Halld61331b2015-02-17 16:35:47 -0800851 sys.exit()
kelvin-onlabf70fd542015-05-07 18:41:40 -0700852
Jon Hall714eeba2015-09-29 17:53:10 -0700853def verifyOnosCell( options ):
Hari Krishnabe4b97b2015-07-15 12:19:43 -0700854 # Verifying onoscell option
Hari Krishna03f530e2015-07-10 17:28:27 -0700855 if options.onoscell:
856 main.onoscell = options.onoscell
Hari Krishnabe4b97b2015-07-15 12:19:43 -0700857 main.onosIPs = []
858 main.mnIP = ""
Jon Hall714eeba2015-09-29 17:53:10 -0700859 cellCMD = ". ~/.profile; cell " + main.onoscell
860 output = subprocess.check_output( ["bash", '-c', cellCMD] )
Hari Krishnabe4b97b2015-07-15 12:19:43 -0700861 splitOutput = output.splitlines()
Jon Hall714eeba2015-09-29 17:53:10 -0700862 for i in range( len( splitOutput ) ):
863 if re.match( "OCN", splitOutput[i] ):
864 mnNode = splitOutput[i].split( "=" )
Hari Krishnabe4b97b2015-07-15 12:19:43 -0700865 main.mnIP = mnNode[1]
Jon Hall714eeba2015-09-29 17:53:10 -0700866 # cell already sorts OC variables in bash, so no need to
867 # sort in TestON
868 if re.match( "OC[1-9]", splitOutput[i] ):
869 onosNodes = splitOutput[i].split( "=" )
Hari Krishnabe4b97b2015-07-15 12:19:43 -0700870 main.onosIPs.append( onosNodes[1] )
Jon Hall714eeba2015-09-29 17:53:10 -0700871 else:
Hari Krishna03f530e2015-07-10 17:28:27 -0700872 main.onoscell = main.FALSE
873
Jon Hall714eeba2015-09-29 17:53:10 -0700874def verifyTestScript( options ):
adminbae64d82013-08-01 10:50:15 -0700875 '''
876 Verifyies test script.
877 '''
Jon Halld61331b2015-02-17 16:35:47 -0800878 main.openspeak = openspeak.OpenSpeak()
Jon Hall714eeba2015-09-29 17:53:10 -0700879 openspeakfile = main.testDir + "/" + main.TEST + "/" + main.TEST + ".ospk"
880 testfile = main.testDir + "/" + main.TEST + "/" + main.TEST + ".py"
881 if os.path.exists( openspeakfile ):
Jon Hall44506242015-07-29 17:40:26 -0700882 # Openspeak file found, compiling to python
Jon Hall714eeba2015-09-29 17:53:10 -0700883 main.openspeak.compiler( openspeakfile=openspeakfile, writetofile=1 )
884 elif os.path.exists( testfile ):
Jon Hall44506242015-07-29 17:40:26 -0700885 # No openspeak found, using python file instead
886 pass
adminbae64d82013-08-01 10:50:15 -0700887 else:
Jon Hall714eeba2015-09-29 17:53:10 -0700888 print "\nThere is no \"" + main.TEST + "\" test script.\nPlease provide a " +\
Jon Hall44506242015-07-29 17:40:26 -0700889 "Python or OpenSpeak test script in the tests folder: " +\
Jon Hall714eeba2015-09-29 17:53:10 -0700890 main.testDir + "/" + main.TEST + "/"
adminbae64d82013-08-01 10:50:15 -0700891 __builtin__.testthread = None
892 main.exit()
Jon Hall714eeba2015-09-29 17:53:10 -0700893 try:
894 testModule = __import__( main.classPath,
895 globals(),
896 locals(),
897 [main.TEST],
898 -1 )
Jon Hall1306a562015-09-04 11:21:24 -0700899 except ImportError:
Jon Hall714eeba2015-09-29 17:53:10 -0700900 print "There was an import error, it might mean that there is " +\
901 "no test named " + main.TEST
Jon Halld61331b2015-02-17 16:35:47 -0800902 main.exit()
adminbae64d82013-08-01 10:50:15 -0700903
Jon Hall714eeba2015-09-29 17:53:10 -0700904 testClass = getattr( testModule, main.TEST )
adminbae64d82013-08-01 10:50:15 -0700905 main.testObject = testClass()
906 load_parser()
Jon Hall714eeba2015-09-29 17:53:10 -0700907 main.params = main.parser.parseParams( main.classPath )
908 main.topology = main.parser.parseTopology( main.classPath )
kelvin-onlabf70fd542015-05-07 18:41:40 -0700909
adminbae64d82013-08-01 10:50:15 -0700910def verifyParams():
Jon Hall714eeba2015-09-29 17:53:10 -0700911 try:
adminbae64d82013-08-01 10:50:15 -0700912 main.params = main.params['PARAMS']
Jon Hall1306a562015-09-04 11:21:24 -0700913 except KeyError:
Jon Hall714eeba2015-09-29 17:53:10 -0700914 print "Error with the params file: Either the file not specified " +\
915 "or the format is not correct"
Jon Halld61331b2015-02-17 16:35:47 -0800916 main.exit()
Jon Hall714eeba2015-09-29 17:53:10 -0700917 try:
adminbae64d82013-08-01 10:50:15 -0700918 main.topology = main.topology['TOPOLOGY']
Jon Hall1306a562015-09-04 11:21:24 -0700919 except KeyError:
Jon Hall714eeba2015-09-29 17:53:10 -0700920 print "Error with the Topology file: Either the file not specified " +\
921 "or the format is not correct"
adminbae64d82013-08-01 10:50:15 -0700922 main.exit()
kelvin-onlabf70fd542015-05-07 18:41:40 -0700923
Jon Hall714eeba2015-09-29 17:53:10 -0700924def load_parser():
adminbae64d82013-08-01 10:50:15 -0700925 '''
926 It facilitates the loading customised parser for topology and params file.
927 It loads parser mentioned in tab named parser of teston.cfg file.
Jon Hall714eeba2015-09-29 17:53:10 -0700928 It also loads default xmlparser if no parser have specified in teston.cfg
929 file.
adminbae64d82013-08-01 10:50:15 -0700930
931 '''
932 confighash = main.configDict
Jon Hall714eeba2015-09-29 17:53:10 -0700933 if 'file' in confighash['config']['parser'] and\
934 'class' in confighash['config']['parser']:
Jon Hall44506242015-07-29 17:40:26 -0700935 path = confighash['config']['parser']['file']
Jon Hall714eeba2015-09-29 17:53:10 -0700936 if path is not None or\
937 confighash['config']['parser']['class'] is not None:
Jon Hall44506242015-07-29 17:40:26 -0700938 try:
939 module = re.sub( r".py\s*$", "", path )
adminbae64d82013-08-01 10:50:15 -0700940 moduleList = module.split("/")
Jon Hall714eeba2015-09-29 17:53:10 -0700941 newModule = ".".join( moduleList[-2:] )
Jon Hall44506242015-07-29 17:40:26 -0700942 parsingClass = confighash['config']['parser']['class']
Jon Hall714eeba2015-09-29 17:53:10 -0700943 parsingModule = __import__( newModule,
944 globals(),
945 locals(),
946 [parsingClass],
947 -1 )
948 parsingClass = getattr( parsingModule, parsingClass )
Jon Hall44506242015-07-29 17:40:26 -0700949 main.parser = parsingClass()
Jon Hall714eeba2015-09-29 17:53:10 -0700950 if hasattr( main.parser, "parseParams" ) and\
951 hasattr( main.parser, "parseTopology" ) and\
952 hasattr( main.parser, "parse" ):
Jon Hall44506242015-07-29 17:40:26 -0700953 pass
954 else:
955 print "Invalid parser format"
adminbae64d82013-08-01 10:50:15 -0700956 main.exit()
Jon Hall44506242015-07-29 17:40:26 -0700957 except ImportError:
Jon Hall714eeba2015-09-29 17:53:10 -0700958 print "Could not find the file " + path +\
959 " using default parser."
Jon Halld61331b2015-02-17 16:35:47 -0800960 load_defaultParser()
Jon Hall714eeba2015-09-29 17:53:10 -0700961 elif confighash['config']['parser']['file'] is None or\
962 confighash['config']['parser']['class'] is None:
Jon Halld61331b2015-02-17 16:35:47 -0800963 load_defaultParser()
adminbae64d82013-08-01 10:50:15 -0700964 else:
965 load_defaultParser()
966
967def load_defaultParser():
968 '''
Jon Hall714eeba2015-09-29 17:53:10 -0700969 It will load the default parser which is xml parser to parse the params and
970 topology file.
adminbae64d82013-08-01 10:50:15 -0700971 '''
972 moduleList = main.parserPath.split("/")
Jon Hall714eeba2015-09-29 17:53:10 -0700973 newModule = ".".join( moduleList[-2:] )
974 try:
Jon Halld61331b2015-02-17 16:35:47 -0800975 parsingClass = main.parsingClass
Jon Hall714eeba2015-09-29 17:53:10 -0700976 parsingModule = __import__( newModule,
977 globals(),
978 locals(),
979 [parsingClass],
980 -1 )
981 parsingClass = getattr( parsingModule, parsingClass )
adminbae64d82013-08-01 10:50:15 -0700982 main.parser = parsingClass()
Jon Hall714eeba2015-09-29 17:53:10 -0700983 if hasattr( main.parser, "parseParams" ) and\
984 hasattr( main.parser, "parseTopology" ) and\
985 hasattr( main.parser, "parse" ):
adminbae64d82013-08-01 10:50:15 -0700986 pass
987 else:
988 main.exit()
adminbae64d82013-08-01 10:50:15 -0700989 except ImportError:
990 print sys.exc_info()[1]
991
Jon Hall714eeba2015-09-29 17:53:10 -0700992def load_logger():
adminbae64d82013-08-01 10:50:15 -0700993 '''
994 It facilitates the loading customised parser for topology and params file.
995 It loads parser mentioned in tab named parser of teston.cfg file.
Jon Hall714eeba2015-09-29 17:53:10 -0700996 It also loads default xmlparser if no parser have specified in teston.cfg
997 file.
adminbae64d82013-08-01 10:50:15 -0700998 '''
999 confighash = main.configDict
Jon Hall714eeba2015-09-29 17:53:10 -07001000 if 'file' in confighash['config']['logger'] and\
1001 'class' in confighash['config']['logger']:
Jon Hall44506242015-07-29 17:40:26 -07001002 path = confighash['config']['logger']['file']
Jon Hall714eeba2015-09-29 17:53:10 -07001003 if path is not None or\
1004 confighash['config']['logger']['class'] is not None:
Jon Hall44506242015-07-29 17:40:26 -07001005 try:
1006 module = re.sub( r".py\s*$", "", path )
Jon Hall714eeba2015-09-29 17:53:10 -07001007 moduleList = module.split( "/" )
1008 newModule = ".".join( moduleList[-2:] )
Jon Hall44506242015-07-29 17:40:26 -07001009 loggerClass = confighash['config']['logger']['class']
Jon Hall714eeba2015-09-29 17:53:10 -07001010 loggerModule = __import__( newModule,
1011 globals(),
1012 locals(),
1013 [loggerClass],
1014 -1 )
1015 loggerClass = getattr( loggerModule, loggerClass )
Jon Hall44506242015-07-29 17:40:26 -07001016 main.logger = loggerClass()
Jon Hall44506242015-07-29 17:40:26 -07001017 except ImportError:
Jon Hall714eeba2015-09-29 17:53:10 -07001018 print "Could not find the file " + path +\
1019 " using default logger."
adminbae64d82013-08-01 10:50:15 -07001020 load_defaultlogger()
Jon Hall714eeba2015-09-29 17:53:10 -07001021 elif confighash['config']['parser']['file'] is None or\
1022 confighash['config']['parser']['class'] is None:
Jon Halld61331b2015-02-17 16:35:47 -08001023 load_defaultlogger()
adminbae64d82013-08-01 10:50:15 -07001024 else:
1025 load_defaultlogger()
1026
1027def load_defaultlogger():
1028 '''
Jon Hall714eeba2015-09-29 17:53:10 -07001029 It will load the default parser which is xml parser to parse the params and
1030 topology file.
adminbae64d82013-08-01 10:50:15 -07001031 '''
1032 moduleList = main.loggerPath.split("/")
Jon Hall714eeba2015-09-29 17:53:10 -07001033 newModule = ".".join( moduleList[-2:] )
1034 try:
Jon Halld61331b2015-02-17 16:35:47 -08001035 loggerClass = main.loggerClass
Jon Hall714eeba2015-09-29 17:53:10 -07001036 loggerModule = __import__( newModule,
1037 globals(),
1038 locals(),
1039 [loggerClass],
1040 -1 )
1041 loggerClass = getattr( loggerModule, loggerClass )
adminbae64d82013-08-01 10:50:15 -07001042 main.logger = loggerClass()
1043
1044 except ImportError:
1045 print sys.exc_info()[1]
Jon Halld61331b2015-02-17 16:35:47 -08001046 main.exit()
adminbae64d82013-08-01 10:50:15 -07001047
Jon Hall714eeba2015-09-29 17:53:10 -07001048def _echo( self ):
adminbae64d82013-08-01 10:50:15 -07001049 print "THIS IS ECHO"