admin | bae64d8 | 2013-08-01 10:50:15 -0700 | [diff] [blame] | 1 | #!/usr/bin/env python |
| 2 | ''' |
| 3 | Created on 20-Dec-2012 |
Jon Hall | 5f15fef | 2015-07-17 14:22:14 -0700 | [diff] [blame] | 4 | |
admin | bae64d8 | 2013-08-01 10:50:15 -0700 | [diff] [blame] | 5 | @author: Anil Kumar (anilkumar.s@paxterrasolutions.com) |
| 6 | |
| 7 | |
| 8 | |
| 9 | TestON is free software: you can redistribute it and/or modify |
| 10 | it under the terms of the GNU General Public License as published by |
| 11 | the Free Software Foundation, either version 2 of the License, or |
| 12 | (at your option) any later version. |
| 13 | |
| 14 | TestON is distributed in the hope that it will be useful, |
| 15 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 17 | GNU General Public License for more details. |
| 18 | |
| 19 | You should have received a copy of the GNU General Public License |
Jon Hall | 4ba53f0 | 2015-07-29 13:07:41 -0700 | [diff] [blame] | 20 | along with TestON. If not, see <http://www.gnu.org/licenses/>. |
admin | bae64d8 | 2013-08-01 10:50:15 -0700 | [diff] [blame] | 21 | |
| 22 | |
| 23 | ''' |
| 24 | |
| 25 | |
| 26 | """ |
| 27 | cli will provide the CLI shell for teston framework. |
| 28 | |
| 29 | A simple command-line interface for TestON. |
| 30 | |
| 31 | The TestON CLI provides a simple console which |
| 32 | makes it easy to launch the test. For example, the command run will execute the test. |
| 33 | |
| 34 | teston> run test DpctlTest |
| 35 | Several useful commands are provided. |
| 36 | """ |
| 37 | |
| 38 | from subprocess import call |
| 39 | from cmd import Cmd |
| 40 | from os import isatty |
| 41 | import sys |
| 42 | import re |
| 43 | import os |
| 44 | import time |
| 45 | import threading |
| 46 | import __builtin__ |
| 47 | import pprint |
| 48 | dump = pprint.PrettyPrinter(indent=4) |
| 49 | __builtin__.testthread = False |
| 50 | introduction = "TestON is the testing framework \nDeveloped by Paxterra Solutions (www.paxterrasolutions.com)" |
Jon Hall | 0bde9ba | 2015-03-19 11:32:57 -0700 | [diff] [blame] | 51 | __builtin__.COLORS = False |
admin | bae64d8 | 2013-08-01 10:50:15 -0700 | [diff] [blame] | 52 | |
Jon Hall | 1dd5a0a | 2015-07-08 10:49:26 -0700 | [diff] [blame] | 53 | path = re.sub( "/bin$", "", sys.path[0] ) |
| 54 | sys.path.insert( 1, path ) |
Jon Hall | 0bde9ba | 2015-03-19 11:32:57 -0700 | [diff] [blame] | 55 | from core.teston import * |
admin | bae64d8 | 2013-08-01 10:50:15 -0700 | [diff] [blame] | 56 | |
| 57 | class CLI( threading.Thread,Cmd,object ): |
| 58 | "command-line interface to execute the test." |
| 59 | |
| 60 | prompt = 'teston> ' |
| 61 | |
| 62 | def __init__( self, teston, stdin=sys.stdin ): |
| 63 | self.teston = teston |
Jon Hall | 0bde9ba | 2015-03-19 11:32:57 -0700 | [diff] [blame] | 64 | |
admin | bae64d8 | 2013-08-01 10:50:15 -0700 | [diff] [blame] | 65 | self._mainevent = threading.Event() |
| 66 | threading.Thread.__init__(self) |
| 67 | self.main_stop = False |
| 68 | self.locals = { 'test': teston } |
| 69 | self.stdin = stdin |
| 70 | Cmd.__init__( self ) |
| 71 | self.pause = False |
| 72 | self.stop = False |
| 73 | __builtin__.cli = self |
| 74 | |
| 75 | def emptyline( self ): |
| 76 | "Don't repeat last command when you hit return." |
| 77 | pass |
| 78 | |
| 79 | helpStr = ( |
| 80 | " teston help" |
| 81 | ) |
| 82 | |
| 83 | def do_help( self, line ): |
| 84 | "Describe available CLI commands." |
| 85 | Cmd.do_help( self, line ) |
| 86 | if line is '': |
| 87 | output( self.helpStr ) |
| 88 | def do_run(self,args): |
| 89 | ''' |
| 90 | run command will execute the test with following optional command line arguments |
| 91 | logdir <directory to store logs in> |
| 92 | testcases <list of testcases separated by comma or range of testcases separated by hypen> |
| 93 | mail <mail-id or list of mail-ids seperated by comma> |
| 94 | example 1, to execute the examples specified in the ~/examples diretory. |
| 95 | ''' |
Jon Hall | 1de6c19 | 2015-09-02 13:50:16 -0700 | [diff] [blame^] | 96 | try: |
| 97 | args = args.split() |
| 98 | options = {} |
| 99 | options = self.parseArgs(args,options) |
| 100 | options = dictToObj(options) |
| 101 | if not testthread: |
| 102 | test = TestThread(options) |
| 103 | test.start() |
| 104 | while test.isAlive: |
| 105 | test.join(1) |
| 106 | else : |
| 107 | print main.TEST+ " test execution paused, please resume that before executing to another test" |
| 108 | except KeyboardInterrupt, SystemExit: |
| 109 | print "Interrupt called, Exiting." |
| 110 | test._Thread__stop() |
| 111 | main.cleanup() |
| 112 | main.exit() |
Jon Hall | 4ba53f0 | 2015-07-29 13:07:41 -0700 | [diff] [blame] | 113 | |
admin | bae64d8 | 2013-08-01 10:50:15 -0700 | [diff] [blame] | 114 | def do_resume(self, line): |
| 115 | ''' |
| 116 | resume command will continue the execution of paused test. |
| 117 | teston>resume |
| 118 | [2013-01-07 23:03:44.640723] [PoxTest] [STEP] 1.1: Checking the host reachability using pingHost |
| 119 | 2013-01-07 23:03:44,858 - PoxTest - INFO - Expected Prompt Found |
| 120 | .... |
| 121 | ''' |
| 122 | if testthread: |
| 123 | testthread.play() |
| 124 | else : |
| 125 | print "There is no test to resume" |
Jon Hall | 4ba53f0 | 2015-07-29 13:07:41 -0700 | [diff] [blame] | 126 | |
admin | bae64d8 | 2013-08-01 10:50:15 -0700 | [diff] [blame] | 127 | def do_nextstep(self,line): |
| 128 | ''' |
Jon Hall | 4ba53f0 | 2015-07-29 13:07:41 -0700 | [diff] [blame] | 129 | nextstep will execute the next-step of the paused test and |
admin | bae64d8 | 2013-08-01 10:50:15 -0700 | [diff] [blame] | 130 | it will pause the test after finishing of step. |
Jon Hall | 4ba53f0 | 2015-07-29 13:07:41 -0700 | [diff] [blame] | 131 | |
admin | bae64d8 | 2013-08-01 10:50:15 -0700 | [diff] [blame] | 132 | teston> nextstep |
| 133 | Will pause the test's execution, after completion of this step..... |
Jon Hall | 4ba53f0 | 2015-07-29 13:07:41 -0700 | [diff] [blame] | 134 | |
admin | bae64d8 | 2013-08-01 10:50:15 -0700 | [diff] [blame] | 135 | teston> [2013-01-07 21:24:26.286601] [PoxTest] [STEP] 1.8: Checking the host reachability using pingHost |
| 136 | 2013-01-07 21:24:26,455 - PoxTest - INFO - Expected Prompt Found |
| 137 | ..... |
| 138 | teston> |
Jon Hall | 4ba53f0 | 2015-07-29 13:07:41 -0700 | [diff] [blame] | 139 | |
admin | bae64d8 | 2013-08-01 10:50:15 -0700 | [diff] [blame] | 140 | ''' |
| 141 | if testthread: |
| 142 | main.log.info("Executing the nextstep, Will pause test execution, after completion of the step") |
| 143 | testthread.play() |
| 144 | time.sleep(.1) |
| 145 | testthread.pause() |
| 146 | else: |
| 147 | print "There is no paused test " |
Jon Hall | 4ba53f0 | 2015-07-29 13:07:41 -0700 | [diff] [blame] | 148 | |
admin | bae64d8 | 2013-08-01 10:50:15 -0700 | [diff] [blame] | 149 | def do_dumpvar(self,line): |
| 150 | ''' |
| 151 | dumpvar will print all the test data in raw format. |
Jon Hall | 4ba53f0 | 2015-07-29 13:07:41 -0700 | [diff] [blame] | 152 | usgae : |
admin | bae64d8 | 2013-08-01 10:50:15 -0700 | [diff] [blame] | 153 | teston>dumpvar main |
| 154 | Here 'main' will be the test object. |
Jon Hall | 4ba53f0 | 2015-07-29 13:07:41 -0700 | [diff] [blame] | 155 | |
| 156 | teston>dumpvar params |
admin | bae64d8 | 2013-08-01 10:50:15 -0700 | [diff] [blame] | 157 | here 'params' will be the parameters specified in the params file. |
Jon Hall | 4ba53f0 | 2015-07-29 13:07:41 -0700 | [diff] [blame] | 158 | |
admin | bae64d8 | 2013-08-01 10:50:15 -0700 | [diff] [blame] | 159 | teston>dumpvar topology |
| 160 | here 'topology' will be topology specification of the test specified in topo file. |
| 161 | ''' |
| 162 | if testthread: |
| 163 | if line == "main": |
| 164 | dump.pprint(vars(main)) |
| 165 | else : |
| 166 | try : |
| 167 | dump.pprint(vars(main)[line]) |
Jon Hall | 1de6c19 | 2015-09-02 13:50:16 -0700 | [diff] [blame^] | 168 | except KeyError as e: |
admin | bae64d8 | 2013-08-01 10:50:15 -0700 | [diff] [blame] | 169 | print e |
| 170 | else : |
| 171 | print "There is no paused test " |
Jon Hall | 4ba53f0 | 2015-07-29 13:07:41 -0700 | [diff] [blame] | 172 | |
admin | bae64d8 | 2013-08-01 10:50:15 -0700 | [diff] [blame] | 173 | def do_currentcase(self,line): |
| 174 | ''' |
| 175 | currentcase will return the current case in the test execution. |
Jon Hall | 4ba53f0 | 2015-07-29 13:07:41 -0700 | [diff] [blame] | 176 | |
admin | bae64d8 | 2013-08-01 10:50:15 -0700 | [diff] [blame] | 177 | teston>currentcase |
| 178 | Currently executing test case is: 2 |
Jon Hall | 4ba53f0 | 2015-07-29 13:07:41 -0700 | [diff] [blame] | 179 | |
admin | bae64d8 | 2013-08-01 10:50:15 -0700 | [diff] [blame] | 180 | ''' |
| 181 | if testthread: |
| 182 | print "Currently executing test case is: "+str(main.CurrentTestCaseNumber) |
| 183 | else : |
| 184 | print "There is no paused test " |
Jon Hall | 4ba53f0 | 2015-07-29 13:07:41 -0700 | [diff] [blame] | 185 | |
| 186 | |
admin | bae64d8 | 2013-08-01 10:50:15 -0700 | [diff] [blame] | 187 | def do_currentstep(self,line): |
| 188 | ''' |
| 189 | currentstep will return the current step in the test execution. |
Jon Hall | 4ba53f0 | 2015-07-29 13:07:41 -0700 | [diff] [blame] | 190 | |
admin | bae64d8 | 2013-08-01 10:50:15 -0700 | [diff] [blame] | 191 | teston>currentstep |
| 192 | Currently executing test step is: 2.3 |
| 193 | ''' |
| 194 | if testthread: |
| 195 | print "Currently executing test step is: "+str(main.CurrentTestCaseNumber)+'.'+str(main.stepCount) |
| 196 | else : |
| 197 | print "There is no paused test " |
Jon Hall | 4ba53f0 | 2015-07-29 13:07:41 -0700 | [diff] [blame] | 198 | |
| 199 | |
admin | bae64d8 | 2013-08-01 10:50:15 -0700 | [diff] [blame] | 200 | def do_stop(self,line): |
| 201 | ''' |
| 202 | Will stop the paused test, if any ! |
| 203 | ''' |
| 204 | if testthread: |
| 205 | testthread.stop() |
Jon Hall | 4ba53f0 | 2015-07-29 13:07:41 -0700 | [diff] [blame] | 206 | |
admin | bae64d8 | 2013-08-01 10:50:15 -0700 | [diff] [blame] | 207 | return 'exited by user command' |
Jon Hall | 4ba53f0 | 2015-07-29 13:07:41 -0700 | [diff] [blame] | 208 | |
admin | bae64d8 | 2013-08-01 10:50:15 -0700 | [diff] [blame] | 209 | def do_gettest(self,line): |
| 210 | ''' |
| 211 | gettest will return the test name which is under execution or recently executed. |
Jon Hall | 4ba53f0 | 2015-07-29 13:07:41 -0700 | [diff] [blame] | 212 | |
admin | bae64d8 | 2013-08-01 10:50:15 -0700 | [diff] [blame] | 213 | Test under execution: |
Jon Hall | 4ba53f0 | 2015-07-29 13:07:41 -0700 | [diff] [blame] | 214 | teston>gettest |
admin | bae64d8 | 2013-08-01 10:50:15 -0700 | [diff] [blame] | 215 | Currently executing Test is: PoxTest |
Jon Hall | 4ba53f0 | 2015-07-29 13:07:41 -0700 | [diff] [blame] | 216 | |
admin | bae64d8 | 2013-08-01 10:50:15 -0700 | [diff] [blame] | 217 | Test recently executed: |
| 218 | Recently executed test is: MininetTest |
| 219 | ''' |
| 220 | try : |
| 221 | if testthread : |
| 222 | print "Currently executing Test is: "+main.TEST |
| 223 | else : |
| 224 | print "Recently executed test is: "+main.TEST |
Jon Hall | 4ba53f0 | 2015-07-29 13:07:41 -0700 | [diff] [blame] | 225 | |
admin | bae64d8 | 2013-08-01 10:50:15 -0700 | [diff] [blame] | 226 | except NameError: |
| 227 | print "There is no previously executed Test" |
Jon Hall | 4ba53f0 | 2015-07-29 13:07:41 -0700 | [diff] [blame] | 228 | |
admin | bae64d8 | 2013-08-01 10:50:15 -0700 | [diff] [blame] | 229 | def do_showlog(self,line): |
| 230 | ''' |
| 231 | showlog will show the test's Log |
| 232 | teston>showlog |
| 233 | Last executed test's log is : //home/openflow/TestON/logs/PoxTest_07_Jan_2013_21_42_11/PoxTest_07_Jan_2013_21_42_11.log |
| 234 | ..... |
| 235 | teston>showlog |
| 236 | Currently executing Test's log is: /home/openflow/TestON/logs/PoxTest_07_Jan_2013_21_46_58/PoxTest_07_Jan_2013_21_46_58.log |
| 237 | ..... |
| 238 | ''' |
| 239 | try : |
| 240 | if testthread : |
| 241 | print "Currently executing Test's log is: "+main.LogFileName |
Jon Hall | 4ba53f0 | 2015-07-29 13:07:41 -0700 | [diff] [blame] | 242 | |
admin | bae64d8 | 2013-08-01 10:50:15 -0700 | [diff] [blame] | 243 | else : |
| 244 | print "Last executed test's log is : "+main.LogFileName |
Jon Hall | 4ba53f0 | 2015-07-29 13:07:41 -0700 | [diff] [blame] | 245 | |
admin | bae64d8 | 2013-08-01 10:50:15 -0700 | [diff] [blame] | 246 | logFile = main.LogFileName |
| 247 | logFileHandler = open(logFile, 'r') |
| 248 | for msg in logFileHandler.readlines() : |
| 249 | print msg, |
Jon Hall | 4ba53f0 | 2015-07-29 13:07:41 -0700 | [diff] [blame] | 250 | |
admin | bae64d8 | 2013-08-01 10:50:15 -0700 | [diff] [blame] | 251 | logFileHandler.close() |
Jon Hall | 4ba53f0 | 2015-07-29 13:07:41 -0700 | [diff] [blame] | 252 | |
admin | bae64d8 | 2013-08-01 10:50:15 -0700 | [diff] [blame] | 253 | except NameError: |
| 254 | print "There is no previously executed Test" |
Jon Hall | 4ba53f0 | 2015-07-29 13:07:41 -0700 | [diff] [blame] | 255 | |
| 256 | |
| 257 | |
admin | bae64d8 | 2013-08-01 10:50:15 -0700 | [diff] [blame] | 258 | def parseArgs(self,args,options): |
| 259 | ''' |
| 260 | This will parse the command line arguments. |
| 261 | ''' |
| 262 | options = self.initOptions(options) |
| 263 | try : |
| 264 | for index, option in enumerate(args): |
| 265 | if index > 0 : |
Hari Krishna | 03f530e | 2015-07-10 17:28:27 -0700 | [diff] [blame] | 266 | if re.match("logdir|mail|example|testdir|testcases|onoscell", option, flags = 0): |
admin | bae64d8 | 2013-08-01 10:50:15 -0700 | [diff] [blame] | 267 | index = index+1 |
| 268 | options[option] = args[index] |
| 269 | options = self.testcasesInRange(index,option,args,options) |
| 270 | else : |
| 271 | options['testname'] = option |
Jon Hall | 1de6c19 | 2015-09-02 13:50:16 -0700 | [diff] [blame^] | 272 | except IndexError as e: |
admin | bae64d8 | 2013-08-01 10:50:15 -0700 | [diff] [blame] | 273 | print e |
Jon Hall | 4ba53f0 | 2015-07-29 13:07:41 -0700 | [diff] [blame] | 274 | |
admin | bae64d8 | 2013-08-01 10:50:15 -0700 | [diff] [blame] | 275 | return options |
Jon Hall | 4ba53f0 | 2015-07-29 13:07:41 -0700 | [diff] [blame] | 276 | |
admin | bae64d8 | 2013-08-01 10:50:15 -0700 | [diff] [blame] | 277 | def initOptions(self,options): |
| 278 | ''' |
| 279 | This will initialize the commandline options. |
| 280 | ''' |
| 281 | options['logdir'] = None |
| 282 | options['mail'] = None |
| 283 | options['example'] = None |
| 284 | options['testdir'] = None |
| 285 | options['testcases'] = None |
Hari Krishna | 03f530e | 2015-07-10 17:28:27 -0700 | [diff] [blame] | 286 | options['onoscell'] = None |
Jon Hall | 4ba53f0 | 2015-07-29 13:07:41 -0700 | [diff] [blame] | 287 | return options |
| 288 | |
admin | bae64d8 | 2013-08-01 10:50:15 -0700 | [diff] [blame] | 289 | def testcasesInRange(self,index,option,args,options): |
| 290 | ''' |
| 291 | This method will handle testcases list,specified in range [1-10]. |
| 292 | ''' |
| 293 | if re.match("testcases",option,1): |
| 294 | testcases = [] |
| 295 | args[index] = re.sub("\[|\]","",args[index],0) |
| 296 | m = re.match("(\d+)\-(\d+)",args[index],flags=0) |
| 297 | if m: |
| 298 | start_case = eval(m.group(1)) |
| 299 | end_case = eval(m.group(2)) |
| 300 | if (start_case <= end_case): |
| 301 | i = start_case |
| 302 | while i <= end_case: |
| 303 | testcases.append(i) |
Jon Hall | 4ba53f0 | 2015-07-29 13:07:41 -0700 | [diff] [blame] | 304 | i= i+1 |
admin | bae64d8 | 2013-08-01 10:50:15 -0700 | [diff] [blame] | 305 | else : |
| 306 | print "Please specify testcases properly like 1-5" |
| 307 | else : |
| 308 | options[option] = args[index] |
| 309 | return options |
| 310 | options[option] = str(testcases) |
Jon Hall | 4ba53f0 | 2015-07-29 13:07:41 -0700 | [diff] [blame] | 311 | |
admin | bae64d8 | 2013-08-01 10:50:15 -0700 | [diff] [blame] | 312 | return options |
Jon Hall | 4ba53f0 | 2015-07-29 13:07:41 -0700 | [diff] [blame] | 313 | |
admin | bae64d8 | 2013-08-01 10:50:15 -0700 | [diff] [blame] | 314 | def cmdloop(self, intro=introduction): |
| 315 | print introduction |
| 316 | while True: |
| 317 | try: |
| 318 | super(CLI, self).cmdloop(intro="") |
| 319 | self.postloop() |
| 320 | except KeyboardInterrupt: |
Jon Hall | 1de6c19 | 2015-09-02 13:50:16 -0700 | [diff] [blame^] | 321 | if testthread: |
| 322 | testthread.pause() |
| 323 | else: |
| 324 | print "KeyboardInterrupt, Exiting." |
| 325 | sys.exit() |
admin | bae64d8 | 2013-08-01 10:50:15 -0700 | [diff] [blame] | 326 | |
| 327 | def do_echo( self, line ): |
| 328 | ''' |
| 329 | Echoing of given input. |
| 330 | ''' |
| 331 | output(line) |
| 332 | |
| 333 | def do_sh( self, line ): |
| 334 | ''' |
| 335 | Run an external shell command |
| 336 | sh pwd |
| 337 | sh ifconfig etc. |
| 338 | ''' |
| 339 | call( line, shell=True ) |
| 340 | |
| 341 | |
| 342 | def do_py( self, line ): |
| 343 | ''' |
| 344 | Evaluate a Python expression. |
Jon Hall | 4ba53f0 | 2015-07-29 13:07:41 -0700 | [diff] [blame] | 345 | |
admin | bae64d8 | 2013-08-01 10:50:15 -0700 | [diff] [blame] | 346 | py main.log.info("Sample Log Information") |
| 347 | 2013-01-07 12:07:26,804 - PoxTest - INFO - Sample Log Information |
Jon Hall | 4ba53f0 | 2015-07-29 13:07:41 -0700 | [diff] [blame] | 348 | |
admin | bae64d8 | 2013-08-01 10:50:15 -0700 | [diff] [blame] | 349 | ''' |
| 350 | try: |
| 351 | exec( line ) |
Jon Hall | 1de6c19 | 2015-09-02 13:50:16 -0700 | [diff] [blame^] | 352 | except Exception as e: |
admin | bae64d8 | 2013-08-01 10:50:15 -0700 | [diff] [blame] | 353 | output( str( e ) + '\n' ) |
Jon Hall | 4ba53f0 | 2015-07-29 13:07:41 -0700 | [diff] [blame] | 354 | |
admin | bae64d8 | 2013-08-01 10:50:15 -0700 | [diff] [blame] | 355 | def do_interpret(self,line): |
| 356 | ''' |
| 357 | interpret will translate the single line openspeak statement to equivalent python script. |
Jon Hall | 4ba53f0 | 2015-07-29 13:07:41 -0700 | [diff] [blame] | 358 | |
admin | bae64d8 | 2013-08-01 10:50:15 -0700 | [diff] [blame] | 359 | teston> interpret ASSERT result EQUALS main.TRUE ONPASS "Ping executed successfully" ONFAIL "Ping failed" |
| 360 | utilities.assert_equals(expect=main.TRUE,actual=result,onpass="Ping executed successfully",onfail="Ping failed") |
Jon Hall | 4ba53f0 | 2015-07-29 13:07:41 -0700 | [diff] [blame] | 361 | |
admin | bae64d8 | 2013-08-01 10:50:15 -0700 | [diff] [blame] | 362 | ''' |
| 363 | from core import openspeak |
| 364 | ospk = openspeak.OpenSpeak() |
| 365 | try : |
| 366 | translated_code = ospk.interpret(text=line) |
| 367 | print translated_code |
Jon Hall | 1de6c19 | 2015-09-02 13:50:16 -0700 | [diff] [blame^] | 368 | except AttributeError as e: |
admin | bae64d8 | 2013-08-01 10:50:15 -0700 | [diff] [blame] | 369 | print 'Dynamic params are not allowed in single statement translations' |
Jon Hall | 4ba53f0 | 2015-07-29 13:07:41 -0700 | [diff] [blame] | 370 | |
admin | bae64d8 | 2013-08-01 10:50:15 -0700 | [diff] [blame] | 371 | def do_do (self,line): |
| 372 | ''' |
| 373 | Do will translate and execute the openspeak statement for the paused test. |
| 374 | do <OpenSpeak statement> |
| 375 | ''' |
| 376 | if testthread: |
| 377 | from core import openspeak |
| 378 | ospk = openspeak.OpenSpeak() |
| 379 | try : |
| 380 | translated_code = ospk.interpret(text=line) |
| 381 | eval(translated_code) |
Jon Hall | 1de6c19 | 2015-09-02 13:50:16 -0700 | [diff] [blame^] | 382 | except ( AttributeError, SyntaxError ) as e: |
| 383 | print 'Dynamic params are not allowed in single statement translations:' |
| 384 | print e |
admin | bae64d8 | 2013-08-01 10:50:15 -0700 | [diff] [blame] | 385 | else : |
| 386 | print "Do will translate and execute the openspeak statement for the paused test.\nPlease use interpret to translate the OpenSpeak statement." |
Jon Hall | 4ba53f0 | 2015-07-29 13:07:41 -0700 | [diff] [blame] | 387 | |
admin | bae64d8 | 2013-08-01 10:50:15 -0700 | [diff] [blame] | 388 | def do_compile(self,line): |
| 389 | ''' |
| 390 | compile will translate the openspeak (.ospk) file into TestON test script (python). |
Jon Hall | 4ba53f0 | 2015-07-29 13:07:41 -0700 | [diff] [blame] | 391 | It will receive the openspeak file path as input and will generate |
| 392 | equivalent test-script file in the same directory. |
| 393 | |
admin | bae64d8 | 2013-08-01 10:50:15 -0700 | [diff] [blame] | 394 | usage: |
| 395 | ----- |
| 396 | teston>compile /home/openflow/TestON/PoxTest.ospk |
Jon Hall | 4ba53f0 | 2015-07-29 13:07:41 -0700 | [diff] [blame] | 397 | |
admin | bae64d8 | 2013-08-01 10:50:15 -0700 | [diff] [blame] | 398 | Auto-generated test-script file is /home/openflow/TestON/PoxTest.py |
| 399 | ''' |
| 400 | from core import openspeak |
Jon Hall | 4ba53f0 | 2015-07-29 13:07:41 -0700 | [diff] [blame] | 401 | openspeak = openspeak.OpenSpeak() |
admin | bae64d8 | 2013-08-01 10:50:15 -0700 | [diff] [blame] | 402 | openspeakfile = line |
| 403 | if os.path.exists(openspeakfile) : |
| 404 | openspeak.compiler(openspeakfile=openspeakfile,writetofile=1) |
| 405 | print "Auto-generated test-script file is "+ re.sub("ospk","py",openspeakfile,0) |
| 406 | else: |
| 407 | print 'There is no such file : '+line |
| 408 | |
| 409 | def do_exit( self, _line ): |
| 410 | "Exit" |
| 411 | if testthread: |
| 412 | testthread.stop() |
Jon Hall | 4ba53f0 | 2015-07-29 13:07:41 -0700 | [diff] [blame] | 413 | |
admin | bae64d8 | 2013-08-01 10:50:15 -0700 | [diff] [blame] | 414 | sys.exit() |
| 415 | |
| 416 | return 'exited by user command' |
| 417 | |
| 418 | def do_quit( self, line ): |
| 419 | "Exit" |
| 420 | return self.do_exit( line ) |
| 421 | |
| 422 | def do_EOF( self, line ): |
| 423 | "Exit" |
| 424 | output( '\n' ) |
| 425 | return self.do_exit( line ) |
| 426 | |
| 427 | def isatty( self ): |
| 428 | "Is our standard input a tty?" |
| 429 | return isatty( self.stdin.fileno() ) |
| 430 | |
| 431 | def do_source( self, line ): |
| 432 | ''' |
| 433 | Read shell commands from an input file and execute them sequentially. |
| 434 | cmdsource.txt : |
Jon Hall | 4ba53f0 | 2015-07-29 13:07:41 -0700 | [diff] [blame] | 435 | |
admin | bae64d8 | 2013-08-01 10:50:15 -0700 | [diff] [blame] | 436 | "pwd |
| 437 | ls " |
Jon Hall | 4ba53f0 | 2015-07-29 13:07:41 -0700 | [diff] [blame] | 438 | |
admin | bae64d8 | 2013-08-01 10:50:15 -0700 | [diff] [blame] | 439 | teston>source /home/openflow/cmdsource.txt |
| 440 | /home/openflow/TestON/bin/ |
| 441 | cli.py __init__.py |
Jon Hall | 4ba53f0 | 2015-07-29 13:07:41 -0700 | [diff] [blame] | 442 | |
admin | bae64d8 | 2013-08-01 10:50:15 -0700 | [diff] [blame] | 443 | ''' |
Jon Hall | 4ba53f0 | 2015-07-29 13:07:41 -0700 | [diff] [blame] | 444 | |
admin | bae64d8 | 2013-08-01 10:50:15 -0700 | [diff] [blame] | 445 | args = line.split() |
| 446 | if len(args) != 1: |
| 447 | error( 'usage: source <file>\n' ) |
| 448 | return |
| 449 | try: |
| 450 | self.inputFile = open( args[ 0 ] ) |
| 451 | while True: |
| 452 | line = self.inputFile.readline() |
| 453 | if len( line ) > 0: |
| 454 | call( line, shell=True ) |
| 455 | else: |
| 456 | break |
| 457 | except IOError: |
| 458 | error( 'error reading file %s\n' % args[ 0 ] ) |
Jon Hall | 4ba53f0 | 2015-07-29 13:07:41 -0700 | [diff] [blame] | 459 | |
admin | bae64d8 | 2013-08-01 10:50:15 -0700 | [diff] [blame] | 460 | def do_updatedriver(self,line): |
| 461 | ''' |
| 462 | updatedriver will update the given driver name which exists into mentioned config file. |
| 463 | It will receive two optional arguments : |
Jon Hall | 4ba53f0 | 2015-07-29 13:07:41 -0700 | [diff] [blame] | 464 | |
| 465 | 1. Config File Path |
admin | bae64d8 | 2013-08-01 10:50:15 -0700 | [diff] [blame] | 466 | 2. Drivers List to be updated. |
Jon Hall | 4ba53f0 | 2015-07-29 13:07:41 -0700 | [diff] [blame] | 467 | |
admin | bae64d8 | 2013-08-01 10:50:15 -0700 | [diff] [blame] | 468 | Default : config file = "~/TestON/config/updatedriver" , |
| 469 | Driver List = all drivers specified in config file . |
| 470 | ''' |
| 471 | args = line.split() |
| 472 | config = '' |
| 473 | drivers = '' |
| 474 | try : |
| 475 | for index, option in enumerate(args): |
| 476 | if option == 'config': |
| 477 | index = index + 1 |
| 478 | config = args[index] |
| 479 | elif option == 'drivers' : |
Jon Hall | 4ba53f0 | 2015-07-29 13:07:41 -0700 | [diff] [blame] | 480 | index = index + 1 |
admin | bae64d8 | 2013-08-01 10:50:15 -0700 | [diff] [blame] | 481 | drivers = args[index] |
| 482 | except IndexError: |
Jon Hall | 4ba53f0 | 2015-07-29 13:07:41 -0700 | [diff] [blame] | 483 | pass |
admin | bae64d8 | 2013-08-01 10:50:15 -0700 | [diff] [blame] | 484 | import updatedriver |
| 485 | converter = updatedriver.UpdateDriver() |
Jon Hall | 4ba53f0 | 2015-07-29 13:07:41 -0700 | [diff] [blame] | 486 | |
admin | bae64d8 | 2013-08-01 10:50:15 -0700 | [diff] [blame] | 487 | if config == '': |
Jon Hall | 4450624 | 2015-07-29 17:40:26 -0700 | [diff] [blame] | 488 | location = os.path.abspath( os.path.dirname( __file__ ) ) |
| 489 | path = re.sub( "(bin)$", "", location ) |
admin | bae64d8 | 2013-08-01 10:50:15 -0700 | [diff] [blame] | 490 | config = path + "/config/updatedriver.cfg" |
| 491 | configDict = converter.configparser(config) |
Jon Hall | 4ba53f0 | 2015-07-29 13:07:41 -0700 | [diff] [blame] | 492 | |
admin | bae64d8 | 2013-08-01 10:50:15 -0700 | [diff] [blame] | 493 | else : |
| 494 | converter.configparser(config) |
| 495 | configDict = converter.configparser(config) |
Jon Hall | 4ba53f0 | 2015-07-29 13:07:41 -0700 | [diff] [blame] | 496 | |
| 497 | |
admin | bae64d8 | 2013-08-01 10:50:15 -0700 | [diff] [blame] | 498 | converter.writeDriver(drivers) |
Jon Hall | 4ba53f0 | 2015-07-29 13:07:41 -0700 | [diff] [blame] | 499 | |
| 500 | |
| 501 | |
| 502 | |
admin | bae64d8 | 2013-08-01 10:50:15 -0700 | [diff] [blame] | 503 | def do_time( self, line ): |
| 504 | "Measure time taken for any command in TestON." |
| 505 | start = time.time() |
| 506 | self.onecmd(line) |
| 507 | elapsed = time.time() - start |
| 508 | self.stdout.write("*** Elapsed time: %0.6f secs\n" % elapsed) |
| 509 | |
| 510 | def default( self, line ): |
| 511 | """Called on an input line when the command prefix is not recognized.""" |
| 512 | first, args, line = self.parseline( line ) |
| 513 | if not args: |
| 514 | return |
| 515 | if args and len(args) > 0 and args[ -1 ] == '\n': |
| 516 | args = args[ :-1 ] |
| 517 | rest = args.split( ' ' ) |
| 518 | |
| 519 | error( '*** Unknown command: %s\n' % first ) |
| 520 | |
| 521 | |
| 522 | |
| 523 | class TestThread(threading.Thread): |
| 524 | ''' |
| 525 | TestThread class will handle the test execution and will communicate with the thread in the do_run. |
| 526 | ''' |
| 527 | def __init__(self,options): |
| 528 | self._stopevent = threading.Event() |
| 529 | threading.Thread.__init__(self) |
| 530 | self.is_stop = False |
| 531 | self.options = options |
| 532 | __builtin__.testthread = self |
| 533 | |
| 534 | def run(self): |
| 535 | ''' |
| 536 | Will execute the test. |
| 537 | ''' |
| 538 | while not self.is_stop : |
| 539 | if not self._stopevent.isSet(): |
| 540 | self.test_on = TestON(self.options) |
| 541 | try : |
| 542 | if self.test_on.init_result: |
| 543 | result = self.test_on.run() |
| 544 | if not self.is_stop : |
| 545 | result = self.test_on.cleanup() |
| 546 | self.is_stop = True |
Jon Hall | 1de6c19 | 2015-09-02 13:50:16 -0700 | [diff] [blame^] | 547 | except KeyboardInterrupt: |
| 548 | print "Recevied Interrupt, cleaning-up the logs and drivers before exiting" |
admin | bae64d8 | 2013-08-01 10:50:15 -0700 | [diff] [blame] | 549 | result = self.test_on.cleanup() |
| 550 | self.is_stop = True |
| 551 | |
Jon Hall | 4ba53f0 | 2015-07-29 13:07:41 -0700 | [diff] [blame] | 552 | __builtin__.testthread = False |
admin | bae64d8 | 2013-08-01 10:50:15 -0700 | [diff] [blame] | 553 | |
| 554 | def pause(self): |
| 555 | ''' |
| 556 | Will pause the test. |
| 557 | ''' |
Jon Hall | 1de6c19 | 2015-09-02 13:50:16 -0700 | [diff] [blame^] | 558 | if not cli.pause: |
| 559 | print "Will pause the test's execution, after completion of this step.....\n\n\n\n" |
| 560 | cli.pause = True |
| 561 | self._stopevent.set() |
| 562 | elif cli.pause and self.is_stop: |
| 563 | print "KeyboardInterrupt, Exiting." |
| 564 | self.test_on.exit() |
| 565 | else: |
| 566 | print "Recevied Interrupt, cleaning-up the logs and drivers before exiting" |
| 567 | result = self.test_on.cleanup() |
| 568 | self.is_stop = True |
admin | bae64d8 | 2013-08-01 10:50:15 -0700 | [diff] [blame] | 569 | |
| 570 | def play(self): |
| 571 | ''' |
| 572 | Will resume the paused test. |
| 573 | ''' |
| 574 | self._stopevent.clear() |
| 575 | cli.pause = False |
Jon Hall | 4ba53f0 | 2015-07-29 13:07:41 -0700 | [diff] [blame] | 576 | |
admin | bae64d8 | 2013-08-01 10:50:15 -0700 | [diff] [blame] | 577 | def stop(self): |
| 578 | ''' |
| 579 | Will stop the test execution. |
| 580 | ''' |
Jon Hall | 4ba53f0 | 2015-07-29 13:07:41 -0700 | [diff] [blame] | 581 | |
admin | bae64d8 | 2013-08-01 10:50:15 -0700 | [diff] [blame] | 582 | print "Stopping the test" |
| 583 | self.is_stop = True |
| 584 | cli.stop = True |
| 585 | __builtin__.testthread = False |
Jon Hall | 4ba53f0 | 2015-07-29 13:07:41 -0700 | [diff] [blame] | 586 | |
admin | bae64d8 | 2013-08-01 10:50:15 -0700 | [diff] [blame] | 587 | def output(msg): |
| 588 | ''' |
| 589 | Simply, print the message in console |
| 590 | ''' |
| 591 | print msg |
| 592 | |
| 593 | def error(msg): |
| 594 | ''' |
| 595 | print the error message. |
| 596 | ''' |
| 597 | print msg |
| 598 | |
| 599 | def dictToObj(dictionary): |
| 600 | ''' |
| 601 | This will facilitates the converting of the dictionary to the object. |
| 602 | This method will help to send options as object format to the test. |
| 603 | ''' |
| 604 | if isinstance(dictionary, list): |
| 605 | dictionary = [dictToObj(x) for x in dictionary] |
| 606 | if not isinstance(dictionary, dict): |
| 607 | return dictionary |
| 608 | class Convert(object): |
| 609 | pass |
| 610 | obj = Convert() |
| 611 | for k in dictionary: |
| 612 | obj.__dict__[k] = dictToObj(dictionary[k]) |
| 613 | return obj |
| 614 | |
| 615 | |
| 616 | if __name__ == '__main__': |
| 617 | if len(sys.argv) > 1: |
Jon Hall | 0bde9ba | 2015-03-19 11:32:57 -0700 | [diff] [blame] | 618 | __builtin__.COLORS = True |
admin | bae64d8 | 2013-08-01 10:50:15 -0700 | [diff] [blame] | 619 | CLI("test").onecmd(' '.join(sys.argv[1:])) |
| 620 | else: |
Jon Hall | 0bde9ba | 2015-03-19 11:32:57 -0700 | [diff] [blame] | 621 | __builtin__.COLORS = False |
admin | bae64d8 | 2013-08-01 10:50:15 -0700 | [diff] [blame] | 622 | CLI("test").cmdloop() |