From 895ff6f4521c3767ce60b75e489edb28aa1abcbe Mon Sep 17 00:00:00 2001 From: Brian O'Connor Date: Mon, 16 Sep 2013 23:58:22 -0700 Subject: [PATCH] adding runner to mininet/test, added test_walkthrough.py --- mininet/test/runner.py | 29 +++ mininet/test/test_walkthrough.py | 330 +++++++++++++++++++++++++++++++ 2 files changed, 359 insertions(+) create mode 100755 mininet/test/runner.py create mode 100755 mininet/test/test_walkthrough.py diff --git a/mininet/test/runner.py b/mininet/test/runner.py new file mode 100755 index 0000000..834a9f4 --- /dev/null +++ b/mininet/test/runner.py @@ -0,0 +1,29 @@ +#!/usr/bin/env python + +""" +Run all mininet core tests + -v : verbose output + -quick : skip tests that take more than ~30 seconds +""" + +import unittest +import os +import sys +from mininet.util import ensureRoot +from mininet.clean import cleanup + +def runTests( testDir, verbosity=1 ): + "discover and run all tests in testDir" + # ensure root and cleanup before starting tests + ensureRoot() + cleanup() + # discover all tests in testDir + testSuite = unittest.defaultTestLoader.discover( testDir ) + # run tests + unittest.TextTestRunner( verbosity=verbosity ).run( testSuite ) + +if __name__ == '__main__': + # get the directory containing example tests + testDir = os.path.dirname( os.path.realpath( __file__ ) ) + verbosity = 2 if '-v' in sys.argv else 1 + runTests( testDir, verbosity ) diff --git a/mininet/test/test_walkthrough.py b/mininet/test/test_walkthrough.py new file mode 100755 index 0000000..ce104a4 --- /dev/null +++ b/mininet/test/test_walkthrough.py @@ -0,0 +1,330 @@ +#!/usr/bin/env python + +""" +Tests for the Mininet Walkthrough + +TODO: missing xterm test +""" + +import unittest +import pexpect +import os +from time import sleep +from mininet.util import quietRun + +class testWalkthrough( unittest.TestCase ): + + prompt = 'mininet>' + + # PART 1 + def testHelp( self ): + "Check the usage message" + p = pexpect.spawn( 'mn -h' ) + index = p.expect( [ 'Usage: mn', pexpect.EOF ] ) + self.assertEqual( index, 0 ) + + def testWireshark( self ): + "Use tshark to test the of dissector" + tshark = pexpect.spawn( 'tshark -i lo -R of' ) + tshark.expect( 'Capturing on lo' ) + mn = pexpect.spawn( 'mn --test pingall' ) + mn.expect( '0% dropped' ) + tshark.expect( 'OFP 74 Hello' ) + tshark.sendintr() + + def testBasic( self ): + "Test basic CLI commands (help, nodes, net, dump)" + p = pexpect.spawn( 'mn' ) + p.expect( self.prompt ) + # help command + p.sendline( 'help' ) + index = p.expect( [ 'commands', self.prompt ] ) + self.assertEqual( index, 0, 'No output for "help" command') + # nodes command + p.sendline( 'nodes' ) + p.expect( '([chs]\d ?){4}' ) + nodes = p.match.group( 0 ).split() + self.assertEqual( len( nodes ), 4, 'No nodes in "nodes" command') + p.expect( self.prompt ) + # net command + p.sendline( 'net' ) + expected = [ x for x in nodes ] + while len( expected ) > 0: + index = p.expect( expected ) + node = p.match.group( 0 ) + expected.remove( node ) + p.expect( '\n' ) + self.assertEqual( len( expected ), 0, '"nodes" and "net" differ') + p.expect( self.prompt ) + # dump command + p.sendline( 'dump' ) + expected = [ '<\w+ (%s)' % n for n in nodes ] + actual = [] + for _ in nodes: + index = p.expect( expected ) + node = p.match.group( 1 ) + actual.append( node ) + p.expect( '\n' ) + self.assertEqual( actual.sort(), nodes.sort(), '"nodes" and "dump" differ' ) + p.expect( self.prompt ) + p.sendline( 'exit' ) + p.wait() + + def testHostCommands( self ): + "Test ifconfig and ps on h1 and s1" + p = pexpect.spawn( 'mn' ) + p.expect( self.prompt ) + interfaces = [ 'h1-eth0', 's1-eth1', '[^-]eth0', 'lo', self.prompt ] + # h1 ifconfig + p.sendline( 'h1 ifconfig -a' ) + ifcount = 0 + while True: + index = p.expect( interfaces ) + if index == 0 or index == 3: + ifcount += 1 + elif index == 1: + self.fail( 's1 interface displayed in "h1 ifconfig"' ) + elif index == 2: + self.fail( 'eth0 displayed in "h1 ifconfig"' ) + else: + break + self.assertEqual( ifcount, 2, 'Missing interfaces on h1') + # s1 ifconfig + p.sendline( 's1 ifconfig -a' ) + ifcount = 0 + while True: + index = p.expect( interfaces ) + if index == 0: + self.fail( 'h1 interface displayed in "s1 ifconfig"' ) + elif index == 1 or index == 2 or index == 3: + ifcount += 1 + else: + break + self.assertEqual( ifcount, 3, 'Missing interfaces on s1') + # h1 ps + p.sendline( 'h1 ps -a' ) + p.expect( self.prompt ) + h1Output = p.before + # s1 ps + p.sendline( 's1 ps -a' ) + p.expect( self.prompt ) + s1Output = p.before + # strip command from ps output + h1Output = h1Output.split( '\n', 1 )[ 1 ] + s1Output = s1Output.split( '\n', 1 )[ 1 ] + self.assertEqual( h1Output, s1Output, 'h1 and s1 "ps" output differs') + p.sendline( 'exit' ) + p.wait() + + def testConnectivity( self ): + "Test ping and pingall" + p = pexpect.spawn( 'mn' ) + p.expect( self.prompt ) + p.sendline( 'h1 ping -c 1 h2' ) + p.expect( '1 packets transmitted, 1 received' ) + p.expect( self.prompt ) + p.sendline( 'pingall' ) + p.expect( '0% dropped' ) + p.expect( self.prompt ) + p.sendline( 'exit' ) + p.wait() + + def testSimpleHTTP( self ): + "Start an HTTP server on h1 and wget from h2" + p = pexpect.spawn( 'mn' ) + p.expect( self.prompt ) + p.sendline( 'h1 python -m SimpleHTTPServer 80 &' ) + p.expect( self.prompt ) + p.sendline( ' h2 wget -O - h1' ) + p.expect( '200 OK' ) + p.expect( self.prompt ) + p.sendline( 'h1 kill %python' ) + p.expect( self.prompt ) + p.sendline( 'exit' ) + p.wait() + + # PART 2 + def testRegressionRun( self ): + "Test pingpair (0% drop) and iperf (bw > 0) regression tests" + # test pingpair + p = pexpect.spawn( 'mn --test pingpair' ) + p.expect( '0% dropped' ) + p.expect( pexpect.EOF ) + # test iperf + p = pexpect.spawn( 'mn --test iperf' ) + p.expect( "Results: \['([\d\.]+) .bits/sec'," ) + bw = float( p.match.group( 1 ) ) + self.assertTrue( bw > 0 ) + p.expect( pexpect.EOF ) + + def testTopoChange( self ): + "Test pingall on single,3 and linear,4 topos" + # testing single,3 + p = pexpect.spawn( 'mn --test pingall --topo single,3' ) + p.expect( '(\d+)/(\d+) received') + received = int( p.match.group( 1 ) ) + sent = int( p.match.group( 2 ) ) + self.assertEqual( sent, 6, 'Wrong number of pings sent in single,3' ) + self.assertEqual( sent, received, 'Dropped packets in single,3') + p.expect( pexpect.EOF ) + # testing linear,4 + p = pexpect.spawn( 'mn --test pingall --topo linear,4' ) + p.expect( '(\d+)/(\d+) received') + received = int( p.match.group( 1 ) ) + sent = int( p.match.group( 2 ) ) + self.assertEqual( sent, 12, 'Wrong number of pings sent in linear,4' ) + self.assertEqual( sent, received, 'Dropped packets in linear,4') + p.expect( pexpect.EOF ) + + def testLinkChange( self ): + "Test TCLink bw and delay" + p = pexpect.spawn( 'mn --link tc,bw=10,delay=10ms' ) + # test bw + p.expect( self.prompt ) + p.sendline( 'iperf' ) + p.expect( "Results: \['([\d\.]+) Mbits/sec'," ) + bw = float( p.match.group( 1 ) ) + self.assertTrue( bw < 10.1, 'Bandwidth > 10 Mb/s') + self.assertTrue( bw > 9.0, 'Bandwidth < 9 Mb/s') + p.expect( self.prompt ) + # test delay + p.sendline( 'h1 ping -c 4 h2' ) + p.expect( 'rtt min/avg/max/mdev = ([\d\.]+)/([\d\.]+)/([\d\.]+)/([\d\.]+) ms' ) + delay = float( p.match.group( 2 ) ) + self.assertTrue( delay > 40, 'Delay < 40ms' ) + self.assertTrue( delay < 45, 'Delay > 40ms' ) + p.expect( self.prompt ) + p.sendline( 'exit' ) + p.wait() + + def testVerbosity( self ): + "Test debug and output verbosity" + # test output + p = pexpect.spawn( 'mn -v output' ) + p.expect( self.prompt ) + self.assertEqual( len( p.before ), 0, 'Too much output for "output"' ) + p.sendline( 'exit' ) + p.wait() + # test debug + p = pexpect.spawn( 'mn -v debug --test none' ) + p.expect( pexpect.EOF ) + lines = p.before.split( '\n' ) + self.assertTrue( len( lines ) > 100, "Debug output is too short" ) + + def testCustomTopo( self ): + "Start Mininet using a custom topo, then run pingall" + custom = os.path.dirname( os.path.realpath( __file__ ) ) + custom = os.path.join( custom, '../../custom/topo-2sw-2host.py' ) + custom = os.path.normpath( custom ) + p = pexpect.spawn( 'mn --custom %s --topo mytopo --test pingall' % custom ) + p.expect( '0% dropped' ) + p.expect( pexpect.EOF ) + + def testStaticMAC( self ): + "Verify that MACs are set to easy to read numbers" + p = pexpect.spawn( 'mn --mac' ) + p.expect( self.prompt ) + for i in range( 1, 3 ): + p.sendline( 'h%d ifconfig' % i ) + p.expect( 'HWaddr 00:00:00:00:00:0%d' % i ) + p.expect( self.prompt ) + + def testSwitches( self ): + "Run iperf test using user and ovsk switches" + switches = [ 'user', 'ovsk' ] + for sw in switches: + p = pexpect.spawn( 'mn --switch %s --test iperf' % sw ) + p.expect( "Results: \['([\d\.]+) .bits/sec'," ) + bw = float( p.match.group( 1 ) ) + self.assertTrue( bw > 0 ) + p.expect( pexpect.EOF ) + + def testBenchmark( self ): + "Run benchmark and verify that it takes less than 2 seconds" + p = pexpect.spawn( 'mn --test none' ) + p.expect( 'completed in ([\d\.]+) seconds' ) + time = float( p.match.group( 1 ) ) + self.assertTrue( time < 2, 'Benchmark takes more than 2 seconds' ) + + def testOwnNamespace( self ): + "Test running user switch in its own namespace" + p = pexpect.spawn( 'mn --innamespace --switch user' ) + p.expect( self.prompt ) + interfaces = [ 'h1-eth0', 's1-eth1', '[^-]eth0', 'lo', self.prompt ] + p.sendline( 's1 ifconfig -a' ) + ifcount = 0 + while True: + index = p.expect( interfaces ) + if index == 1 or index == 3: + ifcount += 1 + elif index == 0: + self.fail( 'h1 interface displayed in "s1 ifconfig"' ) + elif index == 2: + self.fail( 'eth0 displayed in "s1 ifconfig"' ) + else: + break + self.assertEqual( ifcount, 2, 'Missing interfaces on s1' ) + # verify that all hosts a reachable + p.sendline( 'pingall' ) + p.expect( '(\d+)% dropped' ) + dropped = int( p.match.group( 1 ) ) + self.assertEqual( dropped, 0, 'pingall failed') + p.expect( self.prompt ) + p.sendline( 'exit' ) + p.wait() + + # PART 3 + def testPythonInterpreter( self ): + "Test py and px by checking IP for h1 and adding h3" + p = pexpect.spawn( 'mn' ) + p.expect( self.prompt ) + # test host IP + p.sendline( 'py h1.IP()' ) + p.expect( '10.0.0.1' ) + p.expect( self.prompt ) + # test adding host + p.sendline( "px net.addHost('h3')" ) + p.expect( self.prompt ) + p.sendline( "px net.addLink(s1, h3)" ) + p.expect( self.prompt ) + p.sendline( 'net' ) + p.expect( 'h3' ) + p.expect( self.prompt ) + p.sendline( 'py h3.MAC()' ) + p.expect( '([a-f0-9]{2}:?){6}' ) + p.expect( self.prompt ) + p.sendline( 'exit' ) + p.wait() + + def testLink( self ): + "Test link CLI command using ping" + p = pexpect.spawn( 'mn' ) + p.expect( self.prompt ) + p.sendline( 'link s1 h1 down' ) + p.expect( self.prompt ) + p.sendline( 'h1 ping -c 1 h2' ) + p.expect( 'unreachable' ) + p.expect( self.prompt ) + p.sendline( 'link s1 h1 up' ) + p.expect( self.prompt ) + p.sendline( 'h1 ping -c 1 h2' ) + p.expect( '0% packet loss' ) + p.expect( self.prompt ) + p.sendline( 'exit' ) + p.wait() + + @unittest.skipUnless( '1 received' in quietRun( 'ping -c 1 github.com' ), + 'Github is not reachable; cannot download Pox' ) + def testRemoteController( self ): + "Test Mininet using Pox controller" + p = pexpect.spawn( 'test ! -d /tmp/pox && git clone https://github.com/noxrepo/pox.git /tmp/pox') + p.wait() + pox = pexpect.spawn( '/tmp/pox/pox.py forwarding.l2_learning' ) + net = pexpect.spawn( 'mn --controller=remote,ip=127.0.0.1,port=6633 --test pingall' ) + net.expect( '0% dropped' ) + net.expect( pexpect.EOF ) + pox.sendintr() + pox.wait() + +if __name__ == '__main__': + unittest.main() \ No newline at end of file