4 Tests for the Mininet Walkthrough
6 TODO: missing xterm test
12 from mininet.util import quietRun, pexpect
13 from distutils.version import StrictVersion
14 from time import sleep
18 "Return tshark version"
19 versionStr = quietRun( 'tshark -v' )
20 versionMatch = re.findall( r'TShark[^\d]*(\d+.\d+.\d+)', versionStr )
21 return versionMatch[ 0 ]
23 # pylint doesn't understand pexpect.match, unfortunately!
24 # pylint:disable=maybe-no-member
26 class testWalkthrough( unittest.TestCase ):
27 "Test Mininet walkthrough"
33 "Check the usage message"
34 p = pexpect.spawn( 'mn -h' )
35 index = p.expect( [ 'Usage: mn', pexpect.EOF ] )
36 self.assertEqual( index, 0 )
38 def testWireshark( self ):
39 "Use tshark to test the of dissector"
42 if StrictVersion( tsharkVersion() ) < StrictVersion( '1.12.0' ):
43 tshark = pexpect.spawn( 'tshark -i lo -R of' )
45 tshark = pexpect.spawn( 'tshark -i lo -Y openflow_v1' )
46 tshark.expect( [ 'Capturing on lo', "Capturing on 'Loopback'" ] )
47 mn = pexpect.spawn( 'mn --test pingall' )
48 mn.expect( '0% dropped' )
49 tshark.expect( [ '74 Hello', '74 of_hello', '74 Type: OFPT_HELLO' ] )
51 mn.expect( pexpect.EOF )
52 tshark.expect( pexpect.EOF )
54 def testBasic( self ):
55 "Test basic CLI commands (help, nodes, net, dump)"
56 p = pexpect.spawn( 'mn' )
57 p.expect( self.prompt )
60 index = p.expect( [ 'commands', self.prompt ] )
61 self.assertEqual( index, 0, 'No output for "help" command')
64 p.expect( r'([chs]\d ?){4}' )
65 nodes = p.match.group( 0 ).split()
66 self.assertEqual( len( nodes ), 4, 'No nodes in "nodes" command')
67 p.expect( self.prompt )
70 expected = [ x for x in nodes ]
71 while len( expected ) > 0:
72 index = p.expect( expected )
73 node = p.match.group( 0 )
74 expected.remove( node )
76 self.assertEqual( len( expected ), 0, '"nodes" and "net" differ')
77 p.expect( self.prompt )
80 expected = [ r'<\w+ (%s)' % n for n in nodes ]
83 index = p.expect( expected )
84 node = p.match.group( 1 )
87 self.assertEqual( actual.sort(), nodes.sort(),
88 '"nodes" and "dump" differ' )
89 p.expect( self.prompt )
93 def testHostCommands( self ):
94 "Test ifconfig and ps on h1 and s1"
95 p = pexpect.spawn( 'mn' )
96 p.expect( self.prompt )
97 # Third pattern is a local interface beginning with 'eth' or 'en'
98 interfaces = [ r'h1-eth0[:\s]', r's1-eth1[:\s]',
99 r'[^-](eth|en)\w*\d[:\s]', r'lo[:\s]',
102 p.sendline( 'h1 ifconfig -a' )
105 index = p.expect( interfaces )
106 if index == 0 or index == 3:
109 self.fail( 's1 interface displayed in "h1 ifconfig"' )
111 self.fail( 'eth0 displayed in "h1 ifconfig"' )
114 self.assertEqual( ifcount, 2, 'Missing interfaces on h1')
116 p.sendline( 's1 ifconfig -a' )
119 index = p.expect( interfaces )
121 self.fail( 'h1 interface displayed in "s1 ifconfig"' )
122 elif index == 1 or index == 2 or index == 3:
126 self.assertTrue( ifcount <= 3, 'Missing interfaces on s1')
128 p.sendline( "h1 ps -a | egrep -v 'ps|grep'" )
129 p.expect( self.prompt )
132 p.sendline( "s1 ps -a | egrep -v 'ps|grep'" )
133 p.expect( self.prompt )
135 # strip command from ps output and compute diffs
136 h1Output = h1Output.split( '\n' )[ 1: ]
137 s1Output = s1Output.split( '\n' )[ 1: ]
138 diffs = set( h1Output ).difference( set( s1Output ) )
139 # allow up to two diffs to account for daemons, etc.
140 self.assertTrue( len( diffs ) <= 2,
141 'h1 and s1 "ps" output differ too much: %s' % diffs )
145 def testConnectivity( self ):
146 "Test ping and pingall"
147 p = pexpect.spawn( 'mn' )
148 p.expect( self.prompt )
149 p.sendline( 'h1 ping -c 1 h2' )
150 p.expect( '1 packets transmitted, 1 received' )
151 p.expect( self.prompt )
152 p.sendline( 'pingall' )
153 p.expect( '0% dropped' )
154 p.expect( self.prompt )
158 def testSimpleHTTP( self ):
159 "Start an HTTP server on h1 and wget from h2"
160 if 'Python 2' in quietRun( 'python --version' ):
161 httpserver = 'SimpleHTTPServer'
163 httpserver = 'http.server'
164 p = pexpect.spawn( 'mn' )
165 p.expect( self.prompt )
166 p.sendline( 'h1 python -m %s 80 &' % httpserver )
167 # The walkthrough doesn't specify a delay here, and
168 # we also don't read the output (also a possible problem),
169 # but for now let's wait a couple of seconds to make
170 # it less likely to fail due to the race condition.
172 p.expect( self.prompt )
173 p.sendline( ' h2 wget -O - h1' )
175 p.expect( self.prompt )
176 p.sendline( 'h1 kill %python' )
177 p.expect( self.prompt )
182 def testRegressionRun( self ):
183 "Test pingpair (0% drop) and iperf (bw > 0) regression tests"
185 p = pexpect.spawn( 'mn --test pingpair' )
186 p.expect( '0% dropped' )
187 p.expect( pexpect.EOF )
189 p = pexpect.spawn( 'mn --test iperf' )
190 p.expect( r"Results: \['([\d\.]+) .bits/sec'," )
191 bw = float( p.match.group( 1 ) )
192 self.assertTrue( bw > 0 )
193 p.expect( pexpect.EOF )
195 def testTopoChange( self ):
196 "Test pingall on single,3 and linear,4 topos"
198 p = pexpect.spawn( 'mn --test pingall --topo single,3' )
199 p.expect( r'(\d+)/(\d+) received')
200 received = int( p.match.group( 1 ) )
201 sent = int( p.match.group( 2 ) )
202 self.assertEqual( sent, 6, 'Wrong number of pings sent in single,3' )
203 self.assertEqual( sent, received, 'Dropped packets in single,3')
204 p.expect( pexpect.EOF )
206 p = pexpect.spawn( 'mn --test pingall --topo linear,4' )
207 p.expect( r'(\d+)/(\d+) received')
208 received = int( p.match.group( 1 ) )
209 sent = int( p.match.group( 2 ) )
210 self.assertEqual( sent, 12, 'Wrong number of pings sent in linear,4' )
211 self.assertEqual( sent, received, 'Dropped packets in linear,4')
212 p.expect( pexpect.EOF )
214 def testLinkChange( self ):
215 "Test TCLink bw and delay"
216 p = pexpect.spawn( 'mn --link tc,bw=10,delay=10ms' )
218 p.expect( self.prompt )
219 p.sendline( 'iperf' )
220 p.expect( r"Results: \['([\d\.]+) Mbits/sec'," )
221 bw = float( p.match.group( 1 ) )
222 self.assertTrue( bw < 10.1, 'Bandwidth %.2f >= 10.1 Mb/s' % bw )
223 self.assertTrue( bw > 9.0, 'Bandwidth %.2f <= 9 Mb/s' % bw )
224 p.expect( self.prompt )
226 p.sendline( 'h1 ping -c 4 h2' )
227 p.expect( r'rtt min/avg/max/mdev = '
228 r'([\d\.]+)/([\d\.]+)/([\d\.]+)/([\d\.]+) ms' )
229 delay = float( p.match.group( 2 ) )
230 self.assertTrue( delay >= 40, 'Delay < 40ms' )
231 self.assertTrue( delay <= 50, 'Delay > 50ms' )
232 p.expect( self.prompt )
236 def testVerbosity( self ):
237 "Test debug and output verbosity"
239 p = pexpect.spawn( 'mn -v output' )
240 p.expect( self.prompt )
241 self.assertEqual( len( p.before ), 0, 'Too much output for "output"' )
245 p = pexpect.spawn( 'mn -v debug --test none' )
246 p.expect( pexpect.EOF )
247 lines = p.before.split( '\n' )
248 self.assertTrue( len( lines ) > 70, "Debug output is too short" )
250 def testCustomTopo( self ):
251 "Start Mininet using a custom topo, then run pingall"
254 custom = os.path.dirname( os.path.realpath( __file__ ) )
255 custom = os.path.join( custom, '../../custom/topo-2sw-2host.py' )
256 custom = os.path.normpath( custom )
258 'mn --custom %s --topo mytopo --test pingall' % custom )
259 p.expect( '0% dropped' )
260 p.expect( pexpect.EOF )
262 def testStaticMAC( self ):
263 "Verify that MACs are set to easy to read numbers"
264 p = pexpect.spawn( 'mn --mac' )
265 p.expect( self.prompt )
266 for i in range( 1, 3 ):
267 p.sendline( 'h%d ifconfig' % i )
268 p.expect( r'\s00:00:00:00:00:0%d\s' % i )
269 p.expect( self.prompt )
271 p.expect( pexpect.EOF )
273 def testSwitches( self ):
274 "Run iperf test using user and ovsk switches"
275 switches = [ 'user', 'ovsk' ]
277 p = pexpect.spawn( 'mn --switch %s --test iperf' % sw )
278 p.expect( r"Results: \['([\d\.]+) .bits/sec'," )
279 bw = float( p.match.group( 1 ) )
280 self.assertTrue( bw > 0 )
281 p.expect( pexpect.EOF )
283 def testBenchmark( self ):
284 "Run benchmark and verify that it takes less than 2 seconds"
285 p = pexpect.spawn( 'mn --test none' )
286 p.expect( r'completed in ([\d\.]+) seconds' )
287 time = float( p.match.group( 1 ) )
288 self.assertTrue( time < 2, 'Benchmark takes more than 2 seconds' )
290 def testOwnNamespace( self ):
291 "Test running user switch in its own namespace"
292 p = pexpect.spawn( 'mn --innamespace --switch user' )
293 p.expect( self.prompt )
294 interfaces = [ r'h1-eth0[:\s]', r's1-eth1[:\s]',
295 r'[^-](eth|en)\w*\d[:\s]', r'lo[:\s]',
297 p.sendline( 's1 ifconfig -a' )
300 index = p.expect( interfaces )
301 if index == 1 or index == 3:
304 self.fail( 'h1 interface displayed in "s1 ifconfig"' )
306 self.fail( 'eth0 displayed in "s1 ifconfig"' )
309 self.assertEqual( ifcount, 2, 'Missing interfaces on s1' )
310 # verify that all hosts a reachable
311 p.sendline( 'pingall' )
312 p.expect( r'(\d+)% dropped' )
313 dropped = int( p.match.group( 1 ) )
314 self.assertEqual( dropped, 0, 'pingall failed')
315 p.expect( self.prompt )
320 def testPythonInterpreter( self ):
321 "Test py and px by checking IP for h1 and adding h3"
322 p = pexpect.spawn( 'mn' )
323 p.expect( self.prompt )
325 p.sendline( 'py h1.IP()' )
326 p.expect( '10.0.0.1' )
327 p.expect( self.prompt )
329 p.sendline( "px net.addHost('h3')" )
330 p.expect( self.prompt )
331 p.sendline( "px net.addLink(s1, h3)" )
332 p.expect( self.prompt )
335 p.expect( self.prompt )
336 p.sendline( 'py h3.MAC()' )
337 p.expect( '([a-f0-9]{2}:?){6}' )
338 p.expect( self.prompt )
342 def testLink( self ):
343 "Test link CLI command using ping"
344 p = pexpect.spawn( 'mn' )
345 p.expect( self.prompt )
346 p.sendline( 'link s1 h1 down' )
347 p.expect( self.prompt )
348 p.sendline( 'h1 ping -c 1 h2' )
349 p.expect( 'unreachable' )
350 p.expect( self.prompt )
351 p.sendline( 'link s1 h1 up' )
352 p.expect( self.prompt )
353 p.sendline( 'h1 ping -c 1 h2' )
354 p.expect( '0% packet loss' )
355 p.expect( self.prompt )
359 @unittest.skipUnless( os.path.exists( '/tmp/pox' ) or
360 '1 received' in quietRun( 'ping -c 1 github.com' ),
361 'Github is not reachable; cannot download Pox' )
362 def testRemoteController( self ):
363 "Test Mininet using Pox controller"
366 if not os.path.exists( '/tmp/pox' ):
368 'git clone https://github.com/noxrepo/pox.git /tmp/pox' )
369 p.expect( pexpect.EOF )
370 pox = pexpect.spawn( '/tmp/pox/pox.py forwarding.l2_learning' )
372 'mn --controller=remote,ip=127.0.0.1,port=6633 --test pingall' )
373 net.expect( '0% dropped' )
374 net.expect( pexpect.EOF )
379 if __name__ == '__main__':