blob: ae6fc4ef93c50bb1412fff1a4a74a2adc6b640a3 [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
adminbae64d82013-08-01 10:50:15 -070036module = new.module("test")
37import openspeak
Hari Krishnabe4b97b2015-07-15 12:19:43 -070038import subprocess
adminbae64d82013-08-01 10:50:15 -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 )
adminbae64d82013-08-01 10:50:15 -070042drivers_path = path+"drivers/"
43core_path = path+"core"
44tests_path = path+"tests"
45logs_path = path+"logs/"
46config_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.
59 The main tasks are :
60 * 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 '''
63 def __init__(self,options):
64 '''
65 Initialise the component handles specified in the topology file of the specified test.
adminbae64d82013-08-01 10:50:15 -070066 '''
67 # Initialization of the variables.
68 __builtin__.main = self
adminbae64d82013-08-01 10:50:15 -070069 __builtin__.path = path
70 __builtin__.utilities = Utilities()
71 self.TRUE = 1
72 self.FALSE = 0
73 self.ERROR = -1
kelvin-onlabf70fd542015-05-07 18:41:40 -070074 self.NORESULT = 2
adminbae64d82013-08-01 10:50:15 -070075 self.FAIL = False
76 self.PASS = True
kelvin-onlabf70fd542015-05-07 18:41:40 -070077 self.CASERESULT = self.ERROR
78 self.STEPRESULT = self.NORESULT
79 self.stepResults = []
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
adminbae64d82013-08-01 10:50:15 -0700100 self.configparser()
101 verifyOptions(options)
102 load_logger()
103 self.componentDictionary = {}
104 self.componentDictionary = self.topology ['COMPONENT']
105 self.driversList=[]
106 if type(self.componentDictionary) == str :
107 self.componentDictionary = dict(self.componentDictionary)
Jon Hall65844a32015-03-09 19:09:37 -0700108
adminbae64d82013-08-01 10:50:15 -0700109 for component in self.componentDictionary :
110 self.driversList.append(self.componentDictionary[component]['type'])
Jon Hall65844a32015-03-09 19:09:37 -0700111
adminbae64d82013-08-01 10:50:15 -0700112 self.driversList = list(set(self.driversList)) # Removing duplicates.
113 # Checking the test_target option set for the component or not
114 if type(self.componentDictionary) == dict:
115 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
adminbae64d82013-08-01 10:50:15 -0700120 self.logger.initlog(self)
121
122 # Creating Drivers Handles
123 initString = "\n"+"*" * 30+"\n CASE INIT \n"+"*" * 30+"\n"
124 self.log.exact(initString)
125 self.driverObject = {}
126 self.random_order = 111 # Random order id to connect the components
127 components_connect_order = {}
128 #component_list.append()
129 if type(self.componentDictionary) == dict:
130 for component in self.componentDictionary.keys():
131 self.componentDictionary[component]['connect_order'] = self.componentDictionary[component]['connect_order'] if ('connect_order' in self.componentDictionary[component].keys()) else 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, key=lambda key: components_connect_order[key])
135 print ordered_component_list
adminbae64d82013-08-01 10:50:15 -0700136 for component in ordered_component_list:
137 self.componentInit(component)
138
139 def configparser(self):
140 '''
141 It will parse the config file (teston.cfg) and return as dictionary
142 '''
143 matchFileName = re.match(r'(.*)\.cfg', self.configFile, re.M | re.I)
144 if matchFileName:
145 xml = open(self.configFile).read()
146 try :
147 self.configDict = xmldict.xml_to_dict(xml)
148 return self.configDict
Jon Hallfebb1c72015-03-05 13:30:09 -0800149 except Exception:
adminbae64d82013-08-01 10:50:15 -0700150 print "There is no such file to parse " + self.configFile
kelvin-onlabf70fd542015-05-07 18:41:40 -0700151
adminbae64d82013-08-01 10:50:15 -0700152 def componentInit(self,component):
153 '''
154 This method will initialize specified component
155 '''
156 global driver_options
Jon Hall0fc0d452015-07-14 09:49:58 -0700157 self.initiated = False
adminbae64d82013-08-01 10:50:15 -0700158 self.log.info("Creating component Handle: "+component)
Jon Halld61331b2015-02-17 16:35:47 -0800159 driver_options = {}
adminbae64d82013-08-01 10:50:15 -0700160 if 'COMPONENTS' in self.componentDictionary[component].keys():
161 driver_options =dict(self.componentDictionary[component]['COMPONENTS'])
162
163 driver_options['name']=component
164 driverName = self.componentDictionary[component]['type']
165 driver_options ['type'] = driverName
kelvin-onlabf70fd542015-05-07 18:41:40 -0700166
adminbae64d82013-08-01 10:50:15 -0700167 classPath = self.getDriverPath(driverName.lower())
Jon Hall30b82fa2015-03-04 17:15:43 -0800168 driverModule = importlib.import_module(classPath)
adminbae64d82013-08-01 10:50:15 -0700169 driverClass = getattr(driverModule, driverName)
170 driverObject = driverClass()
kelvin-onlabf70fd542015-05-07 18:41:40 -0700171
Hari Krishnabe4b97b2015-07-15 12:19:43 -0700172 if ( "OCN" in self.componentDictionary[component]['host'] and main.onoscell ):
173 self.componentDictionary[component]['host'] = main.mnIP
174
adminbae64d82013-08-01 10:50:15 -0700175 connect_result = driverObject.connect(user_name = self.componentDictionary[component]['user'] if ('user' in self.componentDictionary[component].keys()) else getpass.getuser(),
176 ip_address= self.componentDictionary[component]['host'] if ('host' in self.componentDictionary[component].keys()) else 'localhost',
177 pwd = self.componentDictionary[component]['password'] if ('password' in self.componentDictionary[component].keys()) else 'changeme',
178 port = self.componentDictionary[component]['port'] if ('port' in self.componentDictionary[component].keys()) else None,
179 options = driver_options)
cameron@onlab.us5cc6a372015-05-11 17:18:07 -0700180
adminbae64d82013-08-01 10:50:15 -0700181 if not connect_result:
Jon Hall166e4a42015-08-10 12:03:41 -0700182 self.log.error("Exiting from the test execution because the connecting to the "+component+" component failed.")
Jon Halld61331b2015-02-17 16:35:47 -0800183 self.exit()
kelvin-onlabf70fd542015-05-07 18:41:40 -0700184
adminbae64d82013-08-01 10:50:15 -0700185 vars(self)[component] = driverObject
Jon Hall0fc0d452015-07-14 09:49:58 -0700186 self.initiated = True
kelvin-onlabf70fd542015-05-07 18:41:40 -0700187
adminbae64d82013-08-01 10:50:15 -0700188 def run(self):
189 '''
kelvin-onlabf70fd542015-05-07 18:41:40 -0700190 The Execution of the test script's cases listed in the Test params file will be done here.
191 And Update each test case result.
192 This method will return TRUE if it executed all the test cases successfully,
adminbae64d82013-08-01 10:50:15 -0700193 else will retun FALSE
194 '''
adminbae64d82013-08-01 10:50:15 -0700195 self.testCaseResult = {}
Jon Halla1185982014-09-15 14:55:10 -0700196 self.TOTAL_TC = 0
adminbae64d82013-08-01 10:50:15 -0700197 self.TOTAL_TC_RUN = 0
Jon Halld61331b2015-02-17 16:35:47 -0800198 self.TOTAL_TC_PLANNED = 0
adminbae64d82013-08-01 10:50:15 -0700199 self.TOTAL_TC_NORESULT = 0
200 self.TOTAL_TC_FAIL = 0
201 self.TOTAL_TC_PASS = 0
Jon Halla1185982014-09-15 14:55:10 -0700202 self.TEST_ITERATION = 0
adminbae64d82013-08-01 10:50:15 -0700203 self.stepCount = 0
kelvin-onlabf70fd542015-05-07 18:41:40 -0700204 self.CASERESULT = self.NORESULT
205
Jon Halld61331b2015-02-17 16:35:47 -0800206 import testparser
adminbae64d82013-08-01 10:50:15 -0700207 testFile = self.tests_path + "/"+self.TEST + "/"+self.TEST + ".py"
208 test = testparser.TestParser(testFile)
209 self.testscript = test.testscript
210 self.code = test.getStepCode()
Jon Hallfebb1c72015-03-05 13:30:09 -0800211 repeat= int(self.params['repeat']) if ('repeat' in self.params) else 1
212 self.TOTAL_TC_PLANNED = len(self.testcases_list)*repeat
kelvin-onlabf70fd542015-05-07 18:41:40 -0700213
adminbae64d82013-08-01 10:50:15 -0700214 result = self.TRUE
Jon Hallfebb1c72015-03-05 13:30:09 -0800215 while(repeat):
Jon Halla1185982014-09-15 14:55:10 -0700216 for self.CurrentTestCaseNumber in self.testcases_list:
Jon Halld61331b2015-02-17 16:35:47 -0800217 result = self.runCase(self.CurrentTestCaseNumber)
Jon Hallfebb1c72015-03-05 13:30:09 -0800218 repeat-=1
adminbae64d82013-08-01 10:50:15 -0700219 return result
kelvin-onlabf70fd542015-05-07 18:41:40 -0700220
adminbae64d82013-08-01 10:50:15 -0700221 def runCase(self,testCaseNumber):
222 self.CurrentTestCaseNumber = testCaseNumber
kelvin-onlabf70fd542015-05-07 18:41:40 -0700223 self.CurrentTestCase = ""
224 self.stepResults = []
225 self.stepName = ""
Jon Hall783bbf92015-07-23 14:33:19 -0700226 self.caseExplanation = ""
adminbae64d82013-08-01 10:50:15 -0700227 result = self.TRUE
228 self.stepCount = 0
229 self.EXPERIMENTAL_MODE = self.FALSE
230 self.addCaseHeader()
231 self.testCaseNumber = str(testCaseNumber)
232 stopped = False
233 try :
234 self.stepList = self.code[self.testCaseNumber].keys()
Jon Halld61331b2015-02-17 16:35:47 -0800235 except KeyError:
Jon Hallfebb1c72015-03-05 13:30:09 -0800236 self.log.error("There is no Test-Case "+ self.testCaseNumber)
237 return self.FALSE
kelvin-onlabf70fd542015-05-07 18:41:40 -0700238
adminbae64d82013-08-01 10:50:15 -0700239 self.stepCount = 0
240 while self.stepCount < len(self.code[self.testCaseNumber].keys()):
241 result = self.runStep(self.stepList,self.code,self.testCaseNumber)
Jon Hallfebb1c72015-03-05 13:30:09 -0800242 if result == self.FALSE:
adminbae64d82013-08-01 10:50:15 -0700243 break
Jon Hallfebb1c72015-03-05 13:30:09 -0800244 elif result == self.TRUE:
adminbae64d82013-08-01 10:50:15 -0700245 continue
adminbae64d82013-08-01 10:50:15 -0700246 if not stopped :
kelvin-onlabf70fd542015-05-07 18:41:40 -0700247 if all( self.TRUE == i for i in self.stepResults ):
248 # ALL PASSED
249 self.CASERESULT = self.TRUE
250 elif self.FALSE in self.stepResults:
251 # AT LEAST ONE FAILED
252 self.CASERESULT = self.FALSE
253 elif self.TRUE in self.stepResults:
254 # AT LEAST ONE PASSED
255 self.CASERESULT = self.TRUE
256 else:
257 self.CASERESULT = self.NORESULT
adminbae64d82013-08-01 10:50:15 -0700258 self.testCaseResult[str(self.CurrentTestCaseNumber)] = self.CASERESULT
259 self.logger.updateCaseResults(self)
Jon Hall783bbf92015-07-23 14:33:19 -0700260 self.log.wiki( "<p>" + self.caseExplanation + "</p>" )
261 self.log.summary( self.caseExplanation )
kelvin-onlabf70fd542015-05-07 18:41:40 -0700262 self.log.wiki( "<ul>" )
263 for line in self.stepCache.splitlines():
264 if re.search( " - PASS$", line ):
265 self.log.wiki( "<li>" + line + " <ac:emoticon ac:name=\"tick\" /></li>\n" )
266 elif re.search( " - FAIL$", line ):
267 self.log.wiki( "<li>" + line + " <ac:emoticon ac:name=\"cross\" /></li>\n" )
268 elif re.search( " - No Result$", line ):
269 self.log.wiki( "<li>" + line + " <ac:emoticon ac:name=\"warning\" /></li>\n" )
Jon Hall90627612015-06-09 14:57:02 -0700270 else: # Should only be on fail message
271 self.log.wiki( "<ul><li>" + line + "</li></ul>\n" )
kelvin-onlabf70fd542015-05-07 18:41:40 -0700272 self.log.wiki( "</ul>" )
273 self.log.summary( self.stepCache )
274 self.stepCache = ""
adminbae64d82013-08-01 10:50:15 -0700275 return result
kelvin-onlabf70fd542015-05-07 18:41:40 -0700276
adminbae64d82013-08-01 10:50:15 -0700277 def runStep(self,stepList,code,testCaseNumber):
278 if not cli.pause:
279 try :
280 step = stepList[self.stepCount]
kelvin-onlabf70fd542015-05-07 18:41:40 -0700281 self.STEPRESULT = self.NORESULT
Jon Hall90627612015-06-09 14:57:02 -0700282 self.onFailMsg = "\t\tNo on fail message given"
adminbae64d82013-08-01 10:50:15 -0700283 exec code[testCaseNumber][step] in module.__dict__
284 self.stepCount = self.stepCount + 1
kelvin-onlabf70fd542015-05-07 18:41:40 -0700285 if step > 0:
286 self.stepCache += "\t"+str(testCaseNumber)+"."+str(step)+" "+self.stepName+" - "
287 if self.STEPRESULT == self.TRUE:
288 self.stepCache += "PASS\n"
kelvin-onlabf70fd542015-05-07 18:41:40 -0700289 elif self.STEPRESULT == self.FALSE:
290 self.stepCache += "FAIL\n"
Jon Hall8ce34e82015-06-05 10:41:45 -0700291 # TODO: Print the on-fail statement here
Jon Hall90627612015-06-09 14:57:02 -0700292 self.stepCache += "\t\t" + self.onFailMsg + "\n"
kelvin-onlabf70fd542015-05-07 18:41:40 -0700293 else:
294 self.stepCache += "No Result\n"
kelvin-onlabf70fd542015-05-07 18:41:40 -0700295 self.stepResults.append(self.STEPRESULT)
Jon Hall5b586732015-06-11 11:39:39 -0700296 except StandardError:
Jon Hall40d2cbd2015-06-03 16:24:29 -0700297 self.log.exception( "\nException in the following section of" +
298 " code: " + str(testCaseNumber) + "." +
299 str(step) + ": " + self.stepName )
Jon Hall63604932015-02-26 17:09:50 -0800300 #print code[testCaseNumber][step]
adminbae64d82013-08-01 10:50:15 -0700301 self.stepCount = self.stepCount + 1
kelvin-onlabf70fd542015-05-07 18:41:40 -0700302 self.logger.updateCaseResults(self)
303 #WIKI results
304 self.log.wiki( "<ul>" )
305 for line in self.stepCache.splitlines():
306 if re.search( " - PASS$", line ):
307 self.log.wiki( "<li>" + line + " <ac:emoticon ac:name=\"tick\" /></li>\n" )
308 elif re.search( " - FAIL$", line ):
309 self.log.wiki( "<li>" + line + " <ac:emoticon ac:name=\"cross\" /></li>\n" )
310 elif re.search( " - No Result$", line ):
311 self.log.wiki( "<li>" + line + " <ac:emoticon ac:name=\"warning\" /></li>\n" )
Jon Hall90627612015-06-09 14:57:02 -0700312 else: # Should only be on fail message
313 self.log.wiki( "<ul><li>" + line + "</li></ul>\n" )
kelvin-onlabf70fd542015-05-07 18:41:40 -0700314 self.log.wiki( "</ul>" )
315 #summary results
316 self.log.summary( self.stepCache )
317 self.stepCache = ""
shahshreya957feaa2015-03-23 16:08:29 -0700318 self.cleanup()
Jon Hall00539b12015-04-03 13:55:46 -0700319 self.exit()
adminbae64d82013-08-01 10:50:15 -0700320 return main.TRUE
adminbae64d82013-08-01 10:50:15 -0700321 if cli.stop:
322 cli.stop = False
323 stopped = True
324 self.TOTAL_TC_NORESULT = self.TOTAL_TC_NORESULT + 1
325 self.testCaseResult[str(self.CurrentTestCaseNumber)] = "Stopped"
326 self.logger.updateCaseResults(self)
327 result = self.cleanup()
328 return main.FALSE
kelvin-onlabf70fd542015-05-07 18:41:40 -0700329
adminbae64d82013-08-01 10:50:15 -0700330 def addCaseHeader(self):
331 caseHeader = "\n"+"*" * 30+"\n Result summary for Testcase"+str(self.CurrentTestCaseNumber)+"\n"+"*" * 30+"\n"
Jon Halld61331b2015-02-17 16:35:47 -0800332 self.log.exact(caseHeader)
333 caseHeader = "\n"+"*" * 40 +"\nStart of Test Case"+str(self.CurrentTestCaseNumber)+" : "
adminbae64d82013-08-01 10:50:15 -0700334 for driver in self.componentDictionary.keys():
335 vars(self)[driver+'log'].info(caseHeader)
kelvin-onlabf70fd542015-05-07 18:41:40 -0700336
adminbae64d82013-08-01 10:50:15 -0700337 def addCaseFooter(self):
338 if self.stepCount-1 > 0 :
339 previousStep = " "+str(self.CurrentTestCaseNumber)+"."+str(self.stepCount-1)+": "+ str(self.stepName) + ""
340 stepHeader = "\n"+"*" * 40+"\nEnd of Step "+previousStep+"\n"+"*" * 40+"\n"
kelvin-onlabf70fd542015-05-07 18:41:40 -0700341
adminbae64d82013-08-01 10:50:15 -0700342 caseFooter = "\n"+"*" * 40+"\nEnd of Test case "+str(self.CurrentTestCaseNumber)+"\n"+"*" * 40+"\n"
kelvin-onlabf70fd542015-05-07 18:41:40 -0700343
adminbae64d82013-08-01 10:50:15 -0700344 for driver in self.driversList:
345 vars(self)[driver].write(stepHeader+"\n"+caseFooter)
346
347 def cleanup(self):
348 '''
Jon Hall5b586732015-06-11 11:39:39 -0700349 Print a summary of the current test's results then attempt to release
350 all the component handles and the close opened file handles.
adminbae64d82013-08-01 10:50:15 -0700351
Jon Hall5b586732015-06-11 11:39:39 -0700352 This function shouldbe threadsafe such that cleanup will only be
353 executed once per test.
354
355 This will return TRUE if all the component handles and log handles
356 closed properly, else return FALSE.
adminbae64d82013-08-01 10:50:15 -0700357 '''
358 result = self.TRUE
Jon Hall5b586732015-06-11 11:39:39 -0700359 lock = self.cleanupLock
360 if lock.acquire( False ):
361 try:
362 if self.cleanupFlag is False: # First thread to run this
363 self.cleanupFlag = True
Jon Hall0fc0d452015-07-14 09:49:58 -0700364 if self.initiated:
365 self.logger.testSummary(self)
Jon Hall5b586732015-06-11 11:39:39 -0700366 for component in self.componentDictionary.keys():
367 try :
368 tempObject = vars(self)[component]
369 print "Disconnecting from " + str(tempObject.name) + ": " + \
370 str(tempObject)
371 tempObject.disconnect()
372 except Exception:
373 self.log.exception( "Exception while disconnecting from " +
374 str( component ) )
375 result = self.FALSE
376 # Closing all the driver's session files
377 for driver in self.componentDictionary.keys():
378 try:
379 vars(self)[driver].close_log_handles()
380 except Exception:
381 self.log.exception( "Exception while closing log files for " +
382 str( driver ) )
383 result = self.FALSE
384 else:
385 pass # Someone else already ran through this function
386 finally:
387 lock.release()
388 else: # Someone already has a lock
389 # NOTE: This could cause problems if we don't release the lock
390 # correctly
391 lock.acquire() # Wait for the other thread to finish
392 # NOTE: If we don't wait, exit could be called while the thread
393 # with the lock is still cleaning up
394 lock.release()
adminbae64d82013-08-01 10:50:15 -0700395 return result
Jon Halld61331b2015-02-17 16:35:47 -0800396
adminbae64d82013-08-01 10:50:15 -0700397 def pause(self):
398 '''
399 This function will pause the test's execution, and will continue after user provide 'resume' command.
400 '''
401 __builtin__.testthread.pause()
kelvin-onlabf70fd542015-05-07 18:41:40 -0700402
adminbae64d82013-08-01 10:50:15 -0700403 def onfail(self,*components):
404 '''
kelvin-onlabf70fd542015-05-07 18:41:40 -0700405 When test step failed, calling all the components onfail.
adminbae64d82013-08-01 10:50:15 -0700406 '''
adminbae64d82013-08-01 10:50:15 -0700407 if not components:
408 try :
409 for component in self.componentDictionary.keys():
410 tempObject = vars(self)[component]
411 result = tempObject.onfail()
412 except(Exception),e:
413 print str(e)
414 result = self.FALSE
adminbae64d82013-08-01 10:50:15 -0700415 else:
416 try :
417 for component in components:
418 tempObject = vars(self)[component]
419 result = tempObject.onfail()
420 except(Exception),e:
421 print str(e)
422 result = self.FALSE
kelvin-onlabf70fd542015-05-07 18:41:40 -0700423
adminbae64d82013-08-01 10:50:15 -0700424 def getDriverPath(self,driverName):
425 '''
426 Based on the component 'type' specified in the params , this method will find the absolute path ,
427 by recursively searching the name of the component.
428 '''
429 import commands
430
431 cmd = "find "+drivers_path+" -name "+driverName+".py"
432 result = commands.getoutput(cmd)
kelvin-onlabf70fd542015-05-07 18:41:40 -0700433
adminbae64d82013-08-01 10:50:15 -0700434 result_array = str(result).split('\n')
435 result_count = 0
kelvin-onlabf70fd542015-05-07 18:41:40 -0700436
adminbae64d82013-08-01 10:50:15 -0700437 for drivers_list in result_array:
438 result_count = result_count+1
439 if result_count > 1 :
440 print "found "+driverName+" "+ str(result_count) + " times"+str(result_array)
441 self.exit()
kelvin-onlabf70fd542015-05-07 18:41:40 -0700442
adminbae64d82013-08-01 10:50:15 -0700443 result = re.sub("(.*)drivers","",result)
Jon Hall166e4a42015-08-10 12:03:41 -0700444 result = re.sub("\/\/","/",result)
adminbae64d82013-08-01 10:50:15 -0700445 result = re.sub("\.py","",result)
446 result = re.sub("\.pyc","",result)
447 result = re.sub("\/",".",result)
448 result = "drivers"+result
449 return result
adminbae64d82013-08-01 10:50:15 -0700450
451 def step(self,stepDesc):
452 '''
453 The step information of the test-case will append to the logs.
454 '''
455 previousStep = " "+str(self.CurrentTestCaseNumber)+"."+str(self.stepCount-1)+": "+ str(self.stepName) + ""
456 self.stepName = stepDesc
457
458 stepName = " "+str(self.CurrentTestCaseNumber)+"."+str(self.stepCount)+": "+ str(stepDesc) + ""
459 try :
460 if self.stepCount == 0:
461 stepName = " INIT : Initializing the test case :"+self.CurrentTestCase
462 except AttributeError:
463 stepName = " INIT : Initializing the test case :"+str(self.CurrentTestCaseNumber)
kelvin-onlabf70fd542015-05-07 18:41:40 -0700464
adminbae64d82013-08-01 10:50:15 -0700465 self.log.step(stepName)
466 stepHeader = ""
467 if self.stepCount > 1 :
468 stepHeader = "\n"+"-"*45+"\nEnd of Step "+previousStep+"\n"+"-"*45+"\n"
kelvin-onlabf70fd542015-05-07 18:41:40 -0700469
Jon Halld61331b2015-02-17 16:35:47 -0800470 stepHeader += "\n"+"-"*45+"\nStart of Step"+stepName+"\n"+"-"*45+"\n"
adminbae64d82013-08-01 10:50:15 -0700471 for driver in self.componentDictionary.keys():
472 vars(self)[driver+'log'].info(stepHeader)
kelvin-onlabf70fd542015-05-07 18:41:40 -0700473
adminbae64d82013-08-01 10:50:15 -0700474 def case(self,testCaseName):
475 '''
476 Test's each test-case information will append to the logs.
477 '''
Jon Halld61331b2015-02-17 16:35:47 -0800478 self.CurrentTestCase = testCaseName
adminbae64d82013-08-01 10:50:15 -0700479 testCaseName = " " + str(testCaseName) + ""
480 self.log.case(testCaseName)
Jon Halld61331b2015-02-17 16:35:47 -0800481 caseHeader = testCaseName+"\n"+"*" * 40+"\n"
adminbae64d82013-08-01 10:50:15 -0700482 for driver in self.componentDictionary.keys():
483 vars(self)[driver+'log'].info(caseHeader)
kelvin-onlabf70fd542015-05-07 18:41:40 -0700484
adminbae64d82013-08-01 10:50:15 -0700485 def testDesc(self,description):
486 '''
487 Test description will append to the logs.
488 '''
489 description = "Test Description : " + str (description) + ""
490 self.log.info(description)
kelvin-onlabf70fd542015-05-07 18:41:40 -0700491
adminbae64d82013-08-01 10:50:15 -0700492 def _getTest(self):
493 '''
494 This method will parse the test script to find required test information.
495 '''
496 testFile = self.tests_path + "/"+self.TEST + "/"+self.TEST + ".py"
497 testFileHandler = open(testFile, 'r')
498 testFileList = testFileHandler.readlines()
499 testFileHandler.close()
500 #self.TOTAL_TC_PLANNED = 0
501 counter = 0
502 for index in range(len(testFileList)):
503 lineMatch = re.match('\s+def CASE(\d+)(.*):',testFileList[index],0)
504 if lineMatch:
505 counter = counter + 1
Jon Halla1185982014-09-15 14:55:10 -0700506 self.TC_PLANNED = len(self.testcases_list)
kelvin-onlabf70fd542015-05-07 18:41:40 -0700507
adminbae64d82013-08-01 10:50:15 -0700508 def response_parser(self,response, return_format):
509 ''' It will load the default response parser '''
510 response_dict = {}
511 response_dict = self.response_to_dict(response, return_format)
Jon Halld61331b2015-02-17 16:35:47 -0800512 return_format_string = self.dict_to_return_format(response,return_format,response_dict)
adminbae64d82013-08-01 10:50:15 -0700513 return return_format_string
kelvin-onlabf70fd542015-05-07 18:41:40 -0700514
adminbae64d82013-08-01 10:50:15 -0700515 def response_to_dict(self,response,return_format):
adminbae64d82013-08-01 10:50:15 -0700516 response_dict = {}
517 json_match = re.search('^\s*{', response)
518 xml_match = re.search('^\s*\<', response)
519 ini_match = re.search('^\s*\[', response)
520 if json_match :
Jon Hallfebb1c72015-03-05 13:30:09 -0800521 self.log.info(" Response is in 'JSON' format and Converting to '"+return_format+"' format")
Jon Halld61331b2015-02-17 16:35:47 -0800522 # Formatting the json string
adminbae64d82013-08-01 10:50:15 -0700523 response = re.sub(r"{\s*'?(\w)", r'{"\1', response)
524 response = re.sub(r",\s*'?(\w)", r',"\1', response)
525 response = re.sub(r"(\w)'?\s*:", r'\1":', response)
526 response = re.sub(r":\s*'(\w)'\s*([,}])", r':"\1"\2', response)
adminbae64d82013-08-01 10:50:15 -0700527 try :
528 import json
529 response_dict = json.loads(response)
Jon Hall30b82fa2015-03-04 17:15:43 -0800530 except Exception, e:
Jon Hallfebb1c72015-03-05 13:30:09 -0800531 self.log.exception( e )
532 self.log.error("Json Parser is unable to parse the string")
adminbae64d82013-08-01 10:50:15 -0700533 return response_dict
adminbae64d82013-08-01 10:50:15 -0700534 elif ini_match :
Jon Hallfebb1c72015-03-05 13:30:09 -0800535 self.log.info(" Response is in 'INI' format and Converting to '"+return_format+"' format")
adminbae64d82013-08-01 10:50:15 -0700536 from configobj import ConfigObj
537 response_file = open("respnse_file.temp",'w')
538 response_file.write(response)
Jon Halld61331b2015-02-17 16:35:47 -0800539 response_file.close()
adminbae64d82013-08-01 10:50:15 -0700540 response_dict = ConfigObj("respnse_file.temp")
541 return response_dict
adminbae64d82013-08-01 10:50:15 -0700542 elif xml_match :
Jon Hallfebb1c72015-03-05 13:30:09 -0800543 self.log.info(" Response is in 'XML' format and Converting to '"+return_format+"' format")
adminbae64d82013-08-01 10:50:15 -0700544 try :
adminbae64d82013-08-01 10:50:15 -0700545 response_dict = xmldict.xml_to_dict("<response> "+str(response)+" </response>")
546 except Exception, e:
Jon Hallfebb1c72015-03-05 13:30:09 -0800547 self.log.exception( e )
adminbae64d82013-08-01 10:50:15 -0700548 return response_dict
kelvin-onlabf70fd542015-05-07 18:41:40 -0700549
adminbae64d82013-08-01 10:50:15 -0700550 def dict_to_return_format(self,response,return_format,response_dict):
adminbae64d82013-08-01 10:50:15 -0700551 if return_format =='table' :
552 ''' Will return in table format'''
553 to_do = "Call the table output formatter"
554 global response_table
555 response_table = '\n'
556 response_table = response_table +'\t'.join(response_dict)+"\n"
kelvin-onlabf70fd542015-05-07 18:41:40 -0700557
adminbae64d82013-08-01 10:50:15 -0700558 def get_table(value_to_convert):
559 ''' This will parse the dictionary recusrsively and print as table format'''
560 table_data = ""
561 if type(value_to_convert) == dict :
562 table_data = table_data +'\t'.join(value_to_convert)+"\n"
563 for temp_val in value_to_convert.values() :
564 table_data = table_data + get_table(temp_val)
565 else :
566 table_data = table_data + str(value_to_convert) +"\t"
Jon Halld61331b2015-02-17 16:35:47 -0800567 return table_data
kelvin-onlabf70fd542015-05-07 18:41:40 -0700568
adminbae64d82013-08-01 10:50:15 -0700569 for value in response_dict.values() :
570 response_table = response_table + get_table(value)
Jon Hall88e498c2015-03-06 09:54:35 -0800571 # response_table = response_table + '\t'.join(response_dict.values())
adminbae64d82013-08-01 10:50:15 -0700572 return response_table
kelvin-onlabf70fd542015-05-07 18:41:40 -0700573
adminbae64d82013-08-01 10:50:15 -0700574 elif return_format =='config':
575 ''' Will return in config format'''
576 to_do = 'Call dict to config coverter'
577 response_string = str(response_dict)
578 print response_string
579 response_config = re.sub(",", "\n\t", response_string)
580 response_config = re.sub("u\'", "\'", response_config)
581 response_config = re.sub("{", "", response_config)
582 response_config = re.sub("}", "\n", response_config)
583 response_config = re.sub(":", " =", response_config)
584 return "[response]\n\t "+response_config
adminbae64d82013-08-01 10:50:15 -0700585 elif return_format == 'xml':
586 ''' Will return in xml format'''
adminbae64d82013-08-01 10:50:15 -0700587 response_xml = xmldict.dict_to_xml(response_dict)
588 response_xml = re.sub(">\s*<", ">\n<", response_xml)
589 return "\n"+response_xml
adminbae64d82013-08-01 10:50:15 -0700590 elif return_format == 'json':
591 ''' Will return in json format'''
592 to_do = 'Call dict to xml coverter'
593 import json
594 response_json = json.dumps(response_dict)
595 return response_json
kelvin-onlabf70fd542015-05-07 18:41:40 -0700596
adminbae64d82013-08-01 10:50:15 -0700597 def get_random(self):
598 self.random_order = self.random_order + 1
599 return self.random_order
kelvin-onlabf70fd542015-05-07 18:41:40 -0700600
adminbae64d82013-08-01 10:50:15 -0700601 def exit(self):
602 __builtin__.testthread = None
Jon Hall5b586732015-06-11 11:39:39 -0700603 for thread in threading.enumerate():
604 if thread.isAlive():
605 try:
606 thread._Thread__stop()
607 except:
608 print(str(thread.getName()) + ' could not be terminated' )
adminbae64d82013-08-01 10:50:15 -0700609 sys.exit()
610
611def verifyOptions(options):
612 '''
613 This will verify the command line options and set to default values, if any option not given in command line.
614 '''
615 import pprint
616 pp = pprint.PrettyPrinter(indent=4)
617
Jon Hall88e498c2015-03-06 09:54:35 -0800618 # pp.pprint(options)
adminbae64d82013-08-01 10:50:15 -0700619 verifyTest(options)
620 verifyExample(options)
621 verifyTestScript(options)
622 verifyParams()
623 verifyLogdir(options)
624 verifyMail(options)
625 verifyTestCases(options)
Hari Krishna03f530e2015-07-10 17:28:27 -0700626 verifyOnosCell(options)
adminbae64d82013-08-01 10:50:15 -0700627
628def verifyTest(options):
Jon Hall44506242015-07-29 17:40:26 -0700629 try:
630 if options.testname:
631 main.TEST = options.testname
632 main.classPath = "tests."+main.TEST+"."+main.TEST
633 main.tests_path = tests_path
634 elif options.example:
635 main.TEST = options.example
636 main.tests_path = path+"/examples/"
637 main.classPath = "examples."+main.TEST+"."+main.TEST
638 except AttributeError:
adminbae64d82013-08-01 10:50:15 -0700639 print "Test or Example not specified please specify the --test <test name > or --example <example name>"
Jon Hall5b586732015-06-11 11:39:39 -0700640 main.exit()
adminbae64d82013-08-01 10:50:15 -0700641
642def verifyExample(options):
643 if options.example:
644 main.testDir = path+'/examples/'
645 main.tests_path = path+"/examples/"
646 main.classPath = "examples."+main.TEST+"."+main.TEST
kelvin-onlabf70fd542015-05-07 18:41:40 -0700647
adminbae64d82013-08-01 10:50:15 -0700648def verifyLogdir(options):
Jon Hall88e498c2015-03-06 09:54:35 -0800649 # Verifying Log directory option
adminbae64d82013-08-01 10:50:15 -0700650 if options.logdir:
651 main.logdir = options.logdir
652 else :
Jon Halld61331b2015-02-17 16:35:47 -0800653 main.logdir = main.FALSE
kelvin-onlabf70fd542015-05-07 18:41:40 -0700654
adminbae64d82013-08-01 10:50:15 -0700655def verifyMail(options):
Jon Halld61331b2015-02-17 16:35:47 -0800656 # Checking the mailing list
adminbae64d82013-08-01 10:50:15 -0700657 if options.mail:
658 main.mail = options.mail
659 elif main.params.has_key('mail'):
660 main.mail = main.params['mail']
661 else :
662 main.mail = 'paxweb@paxterrasolutions.com'
663
664def verifyTestCases(options):
Jon Hall88e498c2015-03-06 09:54:35 -0800665 # Getting Test cases list
adminbae64d82013-08-01 10:50:15 -0700666 if options.testcases:
Jon Hallfebb1c72015-03-05 13:30:09 -0800667 testcases_list = options.testcases
Jon Hall88e498c2015-03-06 09:54:35 -0800668 # sys.exit()
adminbae64d82013-08-01 10:50:15 -0700669 testcases_list = re.sub("(\[|\])", "", options.testcases)
670 main.testcases_list = eval(testcases_list+",")
671 else :
672 if 'testcases' in main.params.keys():
Jon Halla1185982014-09-15 14:55:10 -0700673 temp = eval(main.params['testcases']+",")
674 list1=[]
675 if type(temp[0])==list:
Jon Hallfebb1c72015-03-05 13:30:09 -0800676 for test in temp:
677 for testcase in test:
678 if type(testcase)==int:
679 testcase=[testcase]
680 list1.extend(testcase)
681 else :
682 temp=list(temp)
683 for testcase in temp:
684 if type(testcase)==int:
685 testcase=[testcase]
686 list1.extend(testcase)
687 main.testcases_list=list1
adminbae64d82013-08-01 10:50:15 -0700688 else :
689 print "testcases not specifed in params, please provide in params file or 'testcases' commandline argument"
Jon Halld61331b2015-02-17 16:35:47 -0800690 sys.exit()
kelvin-onlabf70fd542015-05-07 18:41:40 -0700691
Hari Krishna03f530e2015-07-10 17:28:27 -0700692def verifyOnosCell(options):
Hari Krishnabe4b97b2015-07-15 12:19:43 -0700693 # Verifying onoscell option
Hari Krishna03f530e2015-07-10 17:28:27 -0700694 if options.onoscell:
695 main.onoscell = options.onoscell
Hari Krishnabe4b97b2015-07-15 12:19:43 -0700696 main.onosIPs = []
697 main.mnIP = ""
698 cellCMD = ". ~/.profile; cell "+main.onoscell
699 output=subprocess.check_output( ["bash", '-c', cellCMD] )
700 splitOutput = output.splitlines()
701 for i in range( len(splitOutput) ):
702 if( re.match( "OCN", splitOutput[i] ) ):
703 mnNode=splitOutput[i].split("=")
704 main.mnIP = mnNode[1]
705 # cell already sorts OC variables in bash, so no need to sort in TestON
706 if( re.match( "OC[1-9]", splitOutput[i] ) ):
707 onosNodes = splitOutput[i].split("=")
708 main.onosIPs.append( onosNodes[1] )
Hari Krishna03f530e2015-07-10 17:28:27 -0700709 else :
710 main.onoscell = main.FALSE
711
adminbae64d82013-08-01 10:50:15 -0700712def verifyTestScript(options):
713 '''
714 Verifyies test script.
715 '''
Jon Halld61331b2015-02-17 16:35:47 -0800716 main.openspeak = openspeak.OpenSpeak()
adminbae64d82013-08-01 10:50:15 -0700717 openspeakfile = main.testDir+"/" + main.TEST + "/" + main.TEST + ".ospk"
718 testfile = main.testDir+"/" + main.TEST + "/" + main.TEST + ".py"
Jon Hall44506242015-07-29 17:40:26 -0700719 if os.path.exists(openspeakfile):
720 # Openspeak file found, compiling to python
adminbae64d82013-08-01 10:50:15 -0700721 main.openspeak.compiler(openspeakfile=openspeakfile,writetofile=1)
722 elif os.path.exists(testfile):
Jon Hall44506242015-07-29 17:40:26 -0700723 # No openspeak found, using python file instead
724 pass
adminbae64d82013-08-01 10:50:15 -0700725 else:
Jon Hall44506242015-07-29 17:40:26 -0700726 print "\nThere is no \""+main.TEST+"\" test script.\nPlease provide a " +\
727 "Python or OpenSpeak test script in the tests folder: " +\
728 main.testDir+"/" + main.TEST + "/"
adminbae64d82013-08-01 10:50:15 -0700729 __builtin__.testthread = None
730 main.exit()
adminbae64d82013-08-01 10:50:15 -0700731 try :
adminbae64d82013-08-01 10:50:15 -0700732 testModule = __import__(main.classPath, globals(), locals(), [main.TEST], -1)
733 except(ImportError):
Jon Hall44506242015-07-29 17:40:26 -0700734 print "There was an import error, it might mean that there is no test named "+main.TEST
Jon Halld61331b2015-02-17 16:35:47 -0800735 main.exit()
adminbae64d82013-08-01 10:50:15 -0700736
737 testClass = getattr(testModule, main.TEST)
738 main.testObject = testClass()
739 load_parser()
Jon Halld61331b2015-02-17 16:35:47 -0800740 main.params = main.parser.parseParams(main.classPath)
741 main.topology = main.parser.parseTopology(main.classPath)
kelvin-onlabf70fd542015-05-07 18:41:40 -0700742
adminbae64d82013-08-01 10:50:15 -0700743def verifyParams():
744 try :
745 main.params = main.params['PARAMS']
746 except(KeyError):
747 print "Error with the params file: Either the file not specified or the format is not correct"
Jon Halld61331b2015-02-17 16:35:47 -0800748 main.exit()
adminbae64d82013-08-01 10:50:15 -0700749 try :
750 main.topology = main.topology['TOPOLOGY']
751 except(KeyError):
752 print "Error with the Topology file: Either the file not specified or the format is not correct"
753 main.exit()
kelvin-onlabf70fd542015-05-07 18:41:40 -0700754
adminbae64d82013-08-01 10:50:15 -0700755def load_parser() :
756 '''
757 It facilitates the loading customised parser for topology and params file.
758 It loads parser mentioned in tab named parser of teston.cfg file.
759 It also loads default xmlparser if no parser have specified in teston.cfg file.
760
761 '''
762 confighash = main.configDict
763 if 'file' in confighash['config']['parser'] and 'class' in confighash['config']['parser']:
Jon Hall44506242015-07-29 17:40:26 -0700764 path = confighash['config']['parser']['file']
765 if path != None or confighash['config']['parser']['class']!= None:
766 try:
767 module = re.sub( r".py\s*$", "", path )
adminbae64d82013-08-01 10:50:15 -0700768 moduleList = module.split("/")
769 newModule = ".".join([moduleList[len(moduleList) - 2],moduleList[len(moduleList) - 1]])
Jon Hall44506242015-07-29 17:40:26 -0700770 parsingClass = confighash['config']['parser']['class']
771 parsingModule = __import__(newModule, globals(), locals(), [parsingClass], -1)
772 parsingClass = getattr(parsingModule, parsingClass)
773 main.parser = parsingClass()
774 #hashobj = main.parser.parseParams(main.classPath)
775 if hasattr(main.parser,"parseParams") and hasattr(main.parser,"parseTopology") and hasattr(main.parser,"parse"):
776 pass
777 else:
778 print "Invalid parser format"
adminbae64d82013-08-01 10:50:15 -0700779 main.exit()
Jon Hall44506242015-07-29 17:40:26 -0700780 except ImportError:
781 print "Could not find the file " + path + " using default parser."
Jon Halld61331b2015-02-17 16:35:47 -0800782 load_defaultParser()
Jon Hall44506242015-07-29 17:40:26 -0700783 elif confighash['config']['parser']['file'] == None or confighash['config']['parser']['class'] == None:
Jon Halld61331b2015-02-17 16:35:47 -0800784 load_defaultParser()
adminbae64d82013-08-01 10:50:15 -0700785 else:
786 load_defaultParser()
787
788def load_defaultParser():
789 '''
790 It will load the default parser which is xml parser to parse the params and topology file.
791 '''
792 moduleList = main.parserPath.split("/")
793 newModule = ".".join([moduleList[len(moduleList) - 2],moduleList[len(moduleList) - 1]])
794 try :
Jon Halld61331b2015-02-17 16:35:47 -0800795 parsingClass = main.parsingClass
adminbae64d82013-08-01 10:50:15 -0700796 parsingModule = __import__(newModule, globals(), locals(), [parsingClass], -1)
797 parsingClass = getattr(parsingModule, parsingClass)
798 main.parser = parsingClass()
799 if hasattr(main.parser,"parseParams") and hasattr(main.parser,"parseTopology") and hasattr(main.parser,"parse") :
800 pass
801 else:
802 main.exit()
803
804 except ImportError:
805 print sys.exc_info()[1]
806
adminbae64d82013-08-01 10:50:15 -0700807def load_logger() :
808 '''
809 It facilitates the loading customised parser for topology and params file.
810 It loads parser mentioned in tab named parser of teston.cfg file.
811 It also loads default xmlparser if no parser have specified in teston.cfg file.
812
813 '''
814 confighash = main.configDict
815 if 'file' in confighash['config']['logger'] and 'class' in confighash['config']['logger']:
Jon Hall44506242015-07-29 17:40:26 -0700816 path = confighash['config']['logger']['file']
817 if path != None or confighash['config']['logger']['class']!= None :
818 try:
819 module = re.sub( r".py\s*$", "", path )
adminbae64d82013-08-01 10:50:15 -0700820 moduleList = module.split("/")
821 newModule = ".".join([moduleList[len(moduleList) - 2],moduleList[len(moduleList) - 1]])
Jon Hall44506242015-07-29 17:40:26 -0700822 loggerClass = confighash['config']['logger']['class']
823 loggerModule = __import__(newModule, globals(), locals(), [loggerClass], -1)
824 loggerClass = getattr(loggerModule, loggerClass)
825 main.logger = loggerClass()
826 #hashobj = main.parser.parseParams(main.classPath)
827 except ImportError:
828 print "Could not find the file " + path + " using default logger."
adminbae64d82013-08-01 10:50:15 -0700829 load_defaultlogger()
Jon Halld61331b2015-02-17 16:35:47 -0800830 elif confighash['config']['parser']['file'] == None or confighash['config']['parser']['class'] == None :
831 load_defaultlogger()
adminbae64d82013-08-01 10:50:15 -0700832 else:
833 load_defaultlogger()
834
835def load_defaultlogger():
836 '''
837 It will load the default parser which is xml parser to parse the params and topology file.
838 '''
839 moduleList = main.loggerPath.split("/")
840 newModule = ".".join([moduleList[len(moduleList) - 2],moduleList[len(moduleList) - 1]])
841 try :
Jon Halld61331b2015-02-17 16:35:47 -0800842 loggerClass = main.loggerClass
adminbae64d82013-08-01 10:50:15 -0700843 loggerModule = __import__(newModule, globals(), locals(), [loggerClass], -1)
844 loggerClass = getattr(loggerModule, loggerClass)
845 main.logger = loggerClass()
846
847 except ImportError:
848 print sys.exc_info()[1]
Jon Halld61331b2015-02-17 16:35:47 -0800849 main.exit()
adminbae64d82013-08-01 10:50:15 -0700850
adminbae64d82013-08-01 10:50:15 -0700851def _echo(self):
852 print "THIS IS ECHO"