From 7bd9a79b12f2867d18824b049edefd6fcedfecae Mon Sep 17 00:00:00 2001
From: Bob Lantz <rlantz@cs.stanford.edu>
Date: Wed, 11 Sep 2013 22:59:50 -0700
Subject: [PATCH] Add --test {test} and --branch {branch} options, and
 exampletest

---
 util/vm/build.py | 113 +++++++++++++++++++++++++++++++++++++----------
 1 file changed, 89 insertions(+), 24 deletions(-)

diff --git a/util/vm/build.py b/util/vm/build.py
index b7db867a..adefd9fa 100755
--- a/util/vm/build.py
+++ b/util/vm/build.py
@@ -30,7 +30,7 @@
 from os import stat, path
 from stat import ST_MODE, ST_SIZE
 from os.path import abspath
-from sys import exit, stdout, argv
+from sys import exit, stdout, argv, modules
 import re
 from glob import glob
 from subprocess import check_output, call, Popen
@@ -38,16 +38,20 @@
 from time import time, strftime, localtime
 import argparse
 from distutils.spawn import find_executable
+import inspect
 
 pexpect = None  # For code check - imported dynamically
 
 # boot can be slooooow!!!! need to debug/optimize somehow
 TIMEOUT=600
 
-# Some configuration
+# Some configuration options
+# Possibly change this to use the parsed arguments instead!
+
 LogToConsole = False        # VM output to console rather than log file
 SaveQCOW2 = False           # Save QCOW2 image rather than deleting it
 NoKVM = False               # Don't use kvm and use emulation instead
+Branch = None               # Branch to update and check out before testing
 
 VMImageDir = os.environ[ 'HOME' ] + '/vm-images'
 
@@ -466,6 +470,27 @@ def coreTest( vm, prompt=Prompt ):
             log( '* Test', test, 'FAILED' )
 
 
+def examplesquickTest( vm, prompt=Prompt ):
+    "Quick test of mininet examples"
+    vm.sendline( 'sudo apt-get install python-pexpect' )
+    vm.expect( prompt )
+    vm.sendline( 'sudo python ~/mininet/examples/test/runner.py -quick' )
+
+
+def examplesfullTest( vm, prompt=Prompt ):
+    "Full (slow) test of mininet examples"
+    vm.sendline( 'sudo apt-get install python-pexpect' )
+    vm.expect( prompt )
+    vm.sendline( 'sudo python ~/mininet/examples/test/runner.py' )
+
+
+def checkOutBranch( vm, branch, prompt=Prompt ):
+    vm.sendline( 'cd ~/mininet; git fetch; git pull --rebase; git checkout '
+                 + branch )
+    vm.expect( prompt )
+    vm.sendline( 'sudo make install' )
+
+
 def interact( vm, prompt=Prompt ):
     "Interact with vm, which is a pexpect object"
     login( vm )
@@ -490,10 +515,7 @@ def interact( vm, prompt=Prompt ):
     log( '* Completed successfully' )
     vm.expect( prompt )
     log( '* Testing Mininet' )
-    sanityTest( vm )
-    vm.expect( prompt )
-    coreTest( vm )
-    vm.expect( prompt )
+    runTests( vm )
     log( '* Shutting down' )
     vm.sendline( 'sync; sudo shutdown -h now' )
     log( '* Waiting for EOF/shutdown' )
@@ -670,33 +692,50 @@ def build( flavor='raring32server' ):
     os.chdir( '..' )
 
 
-def bootAndTest( image, tests=None ):
+def runTests( vm, tests=None, prompt=Prompt ):
+    "Run tests (list) in vm (pexpect object)"
+    if not tests:
+        tests = [ 'sanity', 'core' ]
+    testfns = testDict()
+    for test in tests:
+        if test not in testfns:
+            raise Exception( 'Unknown test: ' + test )
+        log( '* Running test', test )
+        fn = testfns[ test ]
+        fn( vm )
+        vm.expect( prompt )
+
+
+def bootAndRunTests( image, tests=None ):
     """Boot and test VM
-       tests: list of tests (default: sanityTest, coreTest)"""
+       tests: list of tests (default: sanity, core)"""
     bootTestStart = time()
-    if tests is None:
-        tests = [ sanityTest, coreTest ]
     basename = path.basename( image )
     image = abspath( image )
     tmpdir = mkdtemp( prefix='test-' + basename )
-    cow = path.join( tmpdir, image + '-cow.qcow2' )
-    log( '* Creating COW disk' )
+    log( '* Using tmpdir', tmpdir )
+    cow = path.join( tmpdir, basename + '.qcow2' )
+    log( '* Creating COW disk', cow )
     run( 'qemu-img create -f qcow2 -b %s %s' % ( image, cow ) )
     log( '* Extracting kernel and initrd' )
     kernel, initrd = extractKernel( image, flavor=basename, imageDir=tmpdir )
     if LogToConsole:
         logfile = stdout
     else:
-        logfile = NamedTemporaryFile( prefix=image, delete=False )
+        logfile = NamedTemporaryFile( prefix=basename,
+                                      suffix='.testlog', delete=False )
     log( '* Logging VM output to', logfile.name )
     vm = boot( cow=cow, kernel=kernel, initrd=initrd, logfile=logfile )
     prompt = '\$ '
     login( vm )
     log( '* Waiting for VM boot and login' )
     vm.expect( prompt )
-    for test in tests:
-        test( vm )
+    if Branch:
+        checkOutBranch( vm, branch=Branch )
         vm.expect( prompt )
+    log( '* Running tests' )
+    runTests( vm, tests=tests )
+    # runTests eats its last prompt, but maybe it shouldn't...
     log( '* Shutting down' )
     vm.sendline( 'sudo shutdown -h now ' )
     log( '* Waiting for shutdown' )
@@ -709,28 +748,52 @@ def bootAndTest( image, tests=None ):
 
 def buildFlavorString():
     "Return string listing valid build flavors"
-    return 'valid build flavors: %s' % ' '.join( sorted( isoURLs ) )
+    return 'valid build flavors: ( %s )' % ' '.join( sorted( isoURLs ) )
+
+
+def testDict():
+    "Return dict of tests in this module"
+    suffix = 'Test'
+    trim = len( suffix )
+    fdict = dict( [ ( fname[ : -trim ], f ) for fname, f in
+                    inspect.getmembers( modules[ __name__ ],
+                                    inspect.isfunction )
+                  if fname.endswith( suffix ) ] )
+    return fdict
+
+
+def testString():
+    "Return string listing valid tests"
+    return 'valid tests: ( %s )' % ' '.join( testDict().keys() )
 
 
 def parseArgs():
     "Parse command line arguments and run"
-    global LogToConsole, NoKVM
+    global LogToConsole, NoKVM, Branch
     parser = argparse.ArgumentParser( description='Mininet VM build script',
-                                      epilog=buildFlavorString() )
+                                      epilog=buildFlavorString() + ' ' +
+                                      testString() )
     parser.add_argument( '-v', '--verbose', action='store_true',
                         help='send VM output to console rather than log file' )
     parser.add_argument( '-d', '--depend', action='store_true',
                          help='install dependencies for this script' )
     parser.add_argument( '-l', '--list', action='store_true',
-                         help='list valid build flavors' )
+                         help='list valid build flavors and tests' )
     parser.add_argument( '-c', '--clean', action='store_true',
                          help='clean up leftover build junk (e.g. qemu-nbd)' )
     parser.add_argument( '-q', '--qcow2', action='store_true',
                          help='save qcow2 image rather than deleting it' )
     parser.add_argument( '-n', '--nokvm', action='store_true',
                          help="Don't use kvm - use tcg emulation instead" )
-    parser.add_argument( '-t', '--test', metavar='image', action='append',
-                         help='Boot and test a VM image' )
+    parser.add_argument( '-i', '--image', metavar='image', default=[],
+                         action='append',
+                         help='Boot and test an existing VM image' )
+    parser.add_argument( '-t', '--test', metavar='test', default=[],
+                        action='append',
+                        help='specify a test to run' )
+    parser.add_argument( '-b', '--branch', metavar='branch',
+                         help='For an existing VM image, check out and install'
+                         ' this branch before testing' )
     parser.add_argument( 'flavor', nargs='*',
                          help='VM flavor(s) to build (e.g. raring32server)' )
     args = parser.parse_args()
@@ -744,6 +807,8 @@ def parseArgs():
         LogToConsole = True
     if args.nokvm:
         NoKVM = True
+    if args.branch:
+        Branch = args.branch
     for flavor in args.flavor:
         if flavor not in isoURLs:
             print "Unknown build flavor:", flavor
@@ -754,10 +819,10 @@ def parseArgs():
         # except Exception as e:
         # log( '* BUILD FAILED with exception: ', e )
         # exit( 1 )
-    for image in args.test:
-        bootAndTest( image )
+    for image in args.image:
+        bootAndRunTests( image, tests=args.test )
     if not ( args.depend or args.list or args.clean or args.flavor
-             or args.test ):
+             or args.image ):
         parser.print_help()
 
 
-- 
GitLab