1
2 '''
3 Created on 22-Oct-2012
4
5 @author: Anil Kumar (anilkumar.s@paxterrasolutions.com)
6
7 teston is the main module.
8
9 '''
10
11 import sys
12 import getpass
13 import os
14 import re
15 import __builtin__
16 import new
17 import xmldict
18 module = new.module("test")
19 import openspeak
20 global path, drivers_path, core_path, tests_path,logs_path
21 path = re.sub("(core|bin)$", "", os.getcwd())
22 drivers_path = path+"drivers/"
23 core_path = path+"core"
24 tests_path = path+"tests"
25 logs_path = path+"logs/"
26 config_path = path + "config/"
27 sys.path.append(path)
28 sys.path.append( drivers_path)
29 sys.path.append(core_path )
30 sys.path.append(tests_path)
31
32 from core.utilities import Utilities
33
34 import logging
35 import datetime
36 from optparse import OptionParser
37
39 '''
40
41 TestON will initiate the specified test.
42 The main tasks are :
43 * Initiate the required Component handles for the test.
44 * Create Log file Handles.
45
46 '''
48 '''
49 Initialise the component handles specified in the topology file of the specified test.
50
51 '''
52
53 __builtin__.main = self
54
55 __builtin__.path = path
56 __builtin__.utilities = Utilities()
57 self.TRUE = 1
58 self.FALSE = 0
59 self.ERROR = -1
60 self.FAIL = False
61 self.PASS = True
62 self.CASERESULT = self.TRUE
63 self.init_result = self.TRUE
64 self.testResult = "Summary"
65 self.stepName =""
66 self.EXPERIMENTAL_MODE = False
67 self.test_target = None
68 self.lastcommand = None
69 self.testDir = tests_path
70 self.configFile = config_path + "ofa.cfg"
71 self.parsingClass = "xmlparser"
72 self.parserPath = core_path + "/xmlparser"
73 self.loggerPath = core_path + "/logger"
74 self.loggerClass = "Logger"
75 self.logs_path = logs_path
76 self.driver = ''
77
78 self.configparser()
79 verifyOptions(options)
80 load_logger()
81 self.componentDictionary = {}
82 self.componentDictionary = self.topology ['COMPONENT']
83 self.driversList=[]
84 if type(self.componentDictionary) == str :
85 self.componentDictionary = dict(self.componentDictionary)
86
87 for component in self.componentDictionary :
88 self.driversList.append(self.componentDictionary[component]['type'])
89
90 self.driversList = list(set(self.driversList))
91
92 if type(self.componentDictionary) == dict:
93 for component in self.componentDictionary.keys():
94 if 'test_target' in self.componentDictionary[component].keys():
95 self.test_target = component
96
97
98 self.logger.initlog(self)
99
100
101 initString = "\n"+"*" * 30+"\n CASE INIT \n"+"*" * 30+"\n"
102 self.log.exact(initString)
103 self.driverObject = {}
104 if type(self.componentDictionary) == dict:
105 for component in self.componentDictionary.keys():
106 self.componentInit(component)
107
109 '''
110 It will parse the config file (ofa.cfg) and return as dictionary
111 '''
112 matchFileName = re.match(r'(.*)\.cfg', self.configFile, re.M | re.I)
113 if matchFileName:
114 xml = open(self.configFile).read()
115 try :
116 self.configDict = xmldict.xml_to_dict(xml)
117 return self.configDict
118 except :
119 print "There is no such file to parse " + self.configFile
120
122 '''
123 This method will initialize specified component
124 '''
125 global driver_options
126 self.log.info("Creating component Handle: "+component)
127 driver_options = {}
128 if 'COMPONENTS' in self.componentDictionary[component].keys():
129 driver_options =dict(self.componentDictionary[component]['COMPONENTS'])
130
131 driver_options['name']=component
132 driverName = self.componentDictionary[component]['type']
133 driver_options ['type'] = driverName
134
135 classPath = self.getDriverPath(driverName.lower())
136 driverModule = __import__(classPath, globals(), locals(), [driverName.lower()], -1)
137 driverClass = getattr(driverModule, driverName)
138 driverObject = driverClass()
139 connect_result = driverObject.connect(user_name = self.componentDictionary[component]['user'] if ('user' in self.componentDictionary[component].keys()) else getpass.getuser(),
140 ip_address= self.componentDictionary[component]['host'] if ('host' in self.componentDictionary[component].keys()) else 'localhost',
141 pwd = self.componentDictionary[component]['password'] if ('password' in self.componentDictionary[component].keys()) else 'changeme',
142 port = self.componentDictionary[component]['port'] if ('port' in self.componentDictionary[component].keys()) else None,
143 options = driver_options)
144 if not connect_result:
145 self.log.error("Exiting form the test execution because the connecting to the "+component+" component failed.")
146 self.exit()
147
148 vars(self)[component] = driverObject
149
151 '''
152 The Execution of the test script's cases listed in the Test params file will be done here.
153 And Update each test case result.
154 This method will return TRUE if it executed all the test cases successfully,
155 else will retun FALSE
156 '''
157
158 self.testCaseResult = {}
159 self.TOTAL_TC_RUN = 0
160 self.TOTAL_TC_NORESULT = 0
161 self.TOTAL_TC_FAIL = 0
162 self.TOTAL_TC_PASS = 0
163 self.stepCount = 0
164 self.CASERESULT = self.TRUE
165
166 import testparser
167 testFile = self.tests_path + "/"+self.TEST + "/"+self.TEST + ".py"
168 test = testparser.TestParser(testFile)
169 self.testscript = test.testscript
170 self.code = test.getStepCode()
171
172 result = self.TRUE
173 for self.CurrentTestCaseNumber in self.testcases_list:
174 result = self.runCase(self.CurrentTestCaseNumber)
175 return result
176
178 self.CurrentTestCaseNumber = testCaseNumber
179 result = self.TRUE
180 self.stepCount = 0
181 self.EXPERIMENTAL_MODE = self.FALSE
182 self.addCaseHeader()
183 self.testCaseNumber = str(testCaseNumber)
184 stopped = False
185 try :
186 self.stepList = self.code[self.testCaseNumber].keys()
187 except KeyError,e:
188 main.log.error("There is no Test-Case "+ self.testCaseNumber)
189 return main.FALSE
190
191 self.stepCount = 0
192 while self.stepCount < len(self.code[self.testCaseNumber].keys()):
193 result = self.runStep(self.stepList,self.code,self.testCaseNumber)
194 if result == main.FALSE:
195 break
196 elif result == main.TRUE :
197 continue
198
199 if not stopped :
200 self.testCaseResult[str(self.CurrentTestCaseNumber)] = self.CASERESULT
201 self.logger.updateCaseResults(self)
202 return result
203
204 - def runStep(self,stepList,code,testCaseNumber):
205 if not cli.pause:
206 try :
207 step = stepList[self.stepCount]
208 exec code[testCaseNumber][step] in module.__dict__
209 self.stepCount = self.stepCount + 1
210 except TypeError,e:
211 self.stepCount = self.stepCount + 1
212 self.log.error(e)
213 return main.TRUE
214
215 if cli.stop:
216 cli.stop = False
217 stopped = True
218 self.TOTAL_TC_NORESULT = self.TOTAL_TC_NORESULT + 1
219 self.testCaseResult[str(self.CurrentTestCaseNumber)] = "Stopped"
220 self.logger.updateCaseResults(self)
221 result = self.cleanup()
222 return main.FALSE
223
225 caseHeader = "\n"+"*" * 30+"\n Result summary for Testcase"+str(self.CurrentTestCaseNumber)+"\n"+"*" * 30+"\n"
226 self.log.exact(caseHeader)
227 caseHeader = "\n"+"*" * 40 +"\nStart of Test Case"+str(self.CurrentTestCaseNumber)+" : "
228 for driver in self.componentDictionary.keys():
229 vars(self)[driver+'log'].info(caseHeader)
230
240
242 '''
243 Release all the component handles and the close opened file handles.
244 This will return TRUE if all the component handles and log handles closed properly,
245 else return FALSE
246
247 '''
248 result = self.TRUE
249 self.logger.testSummary(self)
250
251
252
253 for driver in self.componentDictionary.keys():
254 vars(self)[driver].close_log_handles()
255
256 utilities.send_mail()
257 try :
258 for component in self.componentDictionary.keys():
259 print "Disconnecting "+str(tempObject)
260 tempObject = vars(self)[component]
261 print "Disconnecting "+str(tempObject)
262 tempObject.disconnect()
263
264
265 except(Exception):
266
267 result = self.FALSE
268
269 return result
270
272 '''
273 This function will pause the test's execution, and will continue after user provide 'resume' command.
274 '''
275 __builtin__.testthread.pause()
276
277 - def onfail(self,*components):
278 '''
279 When test step failed, calling all the components onfail.
280 '''
281
282 if not components:
283 try :
284 for component in self.componentDictionary.keys():
285 tempObject = vars(self)[component]
286 result = tempObject.onfail()
287 except(Exception),e:
288 print str(e)
289 result = self.FALSE
290
291 else:
292 try :
293 for component in components:
294 tempObject = vars(self)[component]
295 result = tempObject.onfail()
296 except(Exception),e:
297 print str(e)
298 result = self.FALSE
299
300
302 '''
303 Based on the component 'type' specified in the params , this method will find the absolute path ,
304 by recursively searching the name of the component.
305 '''
306 import commands
307
308 cmd = "find "+drivers_path+" -name "+driverName+".py"
309 result = commands.getoutput(cmd)
310
311 result_array = str(result).split('\n')
312 result_count = 0
313
314 for drivers_list in result_array:
315 result_count = result_count+1
316 if result_count > 1 :
317 print "found "+driverName+" "+ str(result_count) + " times"+str(result_array)
318 self.exit()
319
320 result = re.sub("(.*)drivers","",result)
321 result = re.sub("\.py","",result)
322 result = re.sub("\.pyc","",result)
323 result = re.sub("\/",".",result)
324 result = "drivers"+result
325 return result
326
327
328 - def step(self,stepDesc):
329 '''
330 The step information of the test-case will append to the logs.
331 '''
332 previousStep = " "+str(self.CurrentTestCaseNumber)+"."+str(self.stepCount-1)+": "+ str(self.stepName) + ""
333 self.stepName = stepDesc
334
335 stepName = " "+str(self.CurrentTestCaseNumber)+"."+str(self.stepCount)+": "+ str(stepDesc) + ""
336 if self.stepCount == 0:
337 stepName = " INIT : Initializing the test case :"+self.CurrentTestCase
338
339 self.log.step(stepName)
340 stepHeader = ""
341 if self.stepCount > 1 :
342 stepHeader = "\n"+"-"*45+"\nEnd of Step "+previousStep+"\n"+"-"*45+"\n"
343
344 stepHeader += "\n"+"-"*45+"\nStart of Step"+stepName+"\n"+"-"*45+"\n"
345 for driver in self.componentDictionary.keys():
346 vars(self)[driver+'log'].info(stepHeader)
347
348 - def case(self,testCaseName):
349 '''
350 Test's each test-case information will append to the logs.
351 '''
352 self.CurrentTestCase = testCaseName
353 testCaseName = " " + str(testCaseName) + ""
354 self.log.case(testCaseName)
355 caseHeader = testCaseName+"\n"+"*" * 40+"\n"
356 for driver in self.componentDictionary.keys():
357 vars(self)[driver+'log'].info(caseHeader)
358
360 '''
361 Test description will append to the logs.
362 '''
363 description = "Test Description : " + str (description) + ""
364 self.log.info(description)
365
367 '''
368 This method will parse the test script to find required test information.
369 '''
370 testFile = self.tests_path + "/"+self.TEST + "/"+self.TEST + ".py"
371 testFileHandler = open(testFile, 'r')
372 testFileList = testFileHandler.readlines()
373 testFileHandler.close()
374
375 counter = 0
376 for index in range(len(testFileList)):
377 lineMatch = re.match('\s+def CASE(\d+)(.*):',testFileList[index],0)
378 if lineMatch:
379 counter = counter + 1
380 self.TOTAL_TC_PLANNED = counter
381
383 __builtin__.testthread = None
384 sys.exit()
385
401
403 if options.testname:
404 main.TEST = options.testname
405 main.classPath = "tests."+main.TEST+"."+main.TEST
406 main.tests_path = tests_path
407 elif options.example :
408 main.TEST = options.example
409 main.tests_path = path+"/examples/"
410 main.classPath = "examples."+main.TEST+"."+main.TEST
411 else :
412 print "Test or Example not specified please specify the --test <test name > or --example <example name>"
413 self.exit()
414
416 if options.example:
417 main.testDir = path+'/examples/'
418 main.tests_path = path+"/examples/"
419 main.classPath = "examples."+main.TEST+"."+main.TEST
420
422
423 if options.logdir:
424 main.logdir = options.logdir
425 else :
426 main.logdir = main.FALSE
427
429
430 if options.mail:
431 main.mail = options.mail
432 elif main.params.has_key('mail'):
433 main.mail = main.params['mail']
434 else :
435 main.mail = 'paxweb@paxterrasolutions.com'
436
438
439 if options.testcases:
440 testcases_list = re.sub("(\[|\])", "", options.testcases)
441 main.testcases_list = eval(testcases_list+",")
442 else :
443 if 'testcases' in main.params.keys():
444 main.params['testcases'] = re.sub("(\[|\])", "", main.params['testcases'])
445 if re.search('\d+', main.params['testcases'], 0):
446 main.testcases_list = eval(main.params['testcases']+",")
447 else :
448 print "Please provide the testcases list in Params file"
449 sys.exit()
450 else :
451 print "testcases not specifed in params, please provide in params file or 'testcases' commandline argument"
452 sys.exit()
453
455 '''
456 Verifyies test script.
457 '''
458 main.openspeak = openspeak.OpenSpeak()
459 openspeakfile = main.testDir+"/" + main.TEST + "/" + main.TEST + ".ospk"
460 testfile = main.testDir+"/" + main.TEST + "/" + main.TEST + ".py"
461 if os.path.exists(openspeakfile) :
462 main.openspeak.compiler(openspeakfile=openspeakfile,writetofile=1)
463 elif os.path.exists(testfile):
464 print ''
465 else:
466 print "\nThere is no :\""+main.TEST+"\" test, Please Provide OpenSpeak Script/ test script"
467 __builtin__.testthread = None
468 main.exit()
469
470 try :
471 testModule = __import__(main.classPath, globals(), locals(), [main.TEST], -1)
472 except(ImportError):
473 print "There is no test like "+main.TEST
474 main.exit()
475
476 testClass = getattr(testModule, main.TEST)
477 main.testObject = testClass()
478 load_parser()
479 main.params = main.parser.parseParams(main.classPath)
480 main.topology = main.parser.parseTopology(main.classPath)
481
483 try :
484 main.params = main.params['PARAMS']
485 except(KeyError):
486 print "Error with the params file: Either the file not specified or the format is not correct"
487 main.exit()
488
489 try :
490 main.topology = main.topology['TOPOLOGY']
491 except(KeyError):
492 print "Error with the Topology file: Either the file not specified or the format is not correct"
493 main.exit()
494
496 '''
497 It facilitates the loading customised parser for topology and params file.
498 It loads parser mentioned in tab named parser of ofa.cfg file.
499 It also loads default xmlparser if no parser have specified in ofa.cfg file.
500
501 '''
502 confighash = main.configDict
503 if 'file' in confighash['config']['parser'] and 'class' in confighash['config']['parser']:
504 if confighash['config']['parser']['file'] != None or confighash['config']['parser']['class']!= None :
505 if os.path.exists(confighash['config']['parser']['file']) :
506 module = re.sub(r".py\s*$","",confighash['config']['parser']['file'])
507 moduleList = module.split("/")
508 newModule = ".".join([moduleList[len(moduleList) - 2],moduleList[len(moduleList) - 1]])
509 try :
510 parsingClass = confighash['config']['parser']['class']
511 parsingModule = __import__(newModule, globals(), locals(), [parsingClass], -1)
512 parsingClass = getattr(parsingModule, parsingClass)
513 main.parser = parsingClass()
514
515 if hasattr(main.parser,"parseParams") and hasattr(main.parser,"parseTopology") and hasattr(main.parser,"parse") :
516
517 pass
518 else:
519 main.exit()
520
521 except ImportError:
522 print sys.exc_info()[1]
523 main.exit()
524 else :
525 print "No Such File Exists !!"+ confighash['config']['parser']['file'] +"using default parser"
526 load_defaultParser()
527 elif confighash['config']['parser']['file'] == None or confighash['config']['parser']['class'] == None :
528 load_defaultParser()
529 else:
530 load_defaultParser()
531
533 '''
534 It will load the default parser which is xml parser to parse the params and topology file.
535 '''
536 moduleList = main.parserPath.split("/")
537 newModule = ".".join([moduleList[len(moduleList) - 2],moduleList[len(moduleList) - 1]])
538 try :
539 parsingClass = main.parsingClass
540 parsingModule = __import__(newModule, globals(), locals(), [parsingClass], -1)
541 parsingClass = getattr(parsingModule, parsingClass)
542 main.parser = parsingClass()
543 if hasattr(main.parser,"parseParams") and hasattr(main.parser,"parseTopology") and hasattr(main.parser,"parse") :
544 pass
545 else:
546 main.exit()
547
548 except ImportError:
549 print sys.exc_info()[1]
550
551
553 '''
554 It facilitates the loading customised parser for topology and params file.
555 It loads parser mentioned in tab named parser of ofa.cfg file.
556 It also loads default xmlparser if no parser have specified in ofa.cfg file.
557
558 '''
559 confighash = main.configDict
560 if 'file' in confighash['config']['logger'] and 'class' in confighash['config']['logger']:
561 if confighash['config']['logger']['file'] != None or confighash['config']['logger']['class']!= None :
562 if os.path.exists(confighash['config']['logger']['file']) :
563 module = re.sub(r".py\s*$","",confighash['config']['logger']['file'])
564 moduleList = module.split("/")
565 newModule = ".".join([moduleList[len(moduleList) - 2],moduleList[len(moduleList) - 1]])
566 try :
567 loggerClass = confighash['config']['logger']['class']
568 loggerModule = __import__(newModule, globals(), locals(), [loggerClass], -1)
569 loggerClass = getattr(loggerModule, loggerClass)
570 main.logger = loggerClass()
571
572
573 except ImportError:
574 print sys.exc_info()[1]
575 else :
576 print "No Such File Exists !!"+confighash['config']['logger']['file']+ "Using default logger"
577 load_defaultlogger()
578 elif confighash['config']['parser']['file'] == None or confighash['config']['parser']['class'] == None :
579 load_defaultlogger()
580 else:
581 load_defaultlogger()
582
584 '''
585 It will load the default parser which is xml parser to parse the params and topology file.
586 '''
587 moduleList = main.loggerPath.split("/")
588 newModule = ".".join([moduleList[len(moduleList) - 2],moduleList[len(moduleList) - 1]])
589 try :
590 loggerClass = main.loggerClass
591 loggerModule = __import__(newModule, globals(), locals(), [loggerClass], -1)
592 loggerClass = getattr(loggerModule, loggerClass)
593 main.logger = loggerClass()
594
595 except ImportError:
596 print sys.exc_info()[1]
597 main.exit()
598
601