Statistics
| Branch: | Tag: | Revision:

mininet / mininet / test / test_walkthrough.py @ 7485b035

History | View | Annotate | Download (12.6 KB)

1 895ff6f4 Brian O'Connor
#!/usr/bin/env python
2
3
"""
4
Tests for the Mininet Walkthrough
5

6
TODO: missing xterm test
7
"""
8
9
import unittest
10
import pexpect
11
import os
12 e3ab3fc2 cody burkard
import re
13 895ff6f4 Brian O'Connor
from mininet.util import quietRun
14 f3411593 Cody Burkard
from distutils.version import StrictVersion
15
16
def tsharkVersion():
17 1471da95 Bob Lantz
    "Return tshark version"
18 f3411593 Cody Burkard
    versionStr = quietRun( 'tshark -v' )
19 1471da95 Bob Lantz
    versionMatch = re.findall( r'TShark \d+.\d+.\d+', versionStr )[0]
20 f3411593 Cody Burkard
    return versionMatch.split()[ 1 ]
21 895ff6f4 Brian O'Connor
22 18aab5b7 Bob Lantz
# pylint doesn't understand pexpect.match, unfortunately!
23
# pylint:disable=maybe-no-member
24
25 895ff6f4 Brian O'Connor
class testWalkthrough( unittest.TestCase ):
26 1471da95 Bob Lantz
    "Test Mininet walkthrough"
27 895ff6f4 Brian O'Connor
28
    prompt = 'mininet>'
29
30
    # PART 1
31
    def testHelp( self ):
32
        "Check the usage message"
33
        p = pexpect.spawn( 'mn -h' )
34
        index = p.expect( [ 'Usage: mn', pexpect.EOF ] )
35
        self.assertEqual( index, 0 )
36
37
    def testWireshark( self ):
38
        "Use tshark to test the of dissector"
39 18aab5b7 Bob Lantz
        # Satisfy pylint
40 1471da95 Bob Lantz
        assert self
41 f3411593 Cody Burkard
        if StrictVersion( tsharkVersion() ) < StrictVersion( '1.12.0' ):
42
            tshark = pexpect.spawn( 'tshark -i lo -R of' )
43
        else:
44
            tshark = pexpect.spawn( 'tshark -i lo -Y openflow_v1' )
45 61c144b9 Bob Lantz
        tshark.expect( [ 'Capturing on lo', "Capturing on 'Loopback'" ] )
46 895ff6f4 Brian O'Connor
        mn = pexpect.spawn( 'mn --test pingall' )
47
        mn.expect( '0% dropped' )
48 f3411593 Cody Burkard
        tshark.expect( [ '74 Hello', '74 of_hello', '74 Type: OFPT_HELLO' ] )
49 895ff6f4 Brian O'Connor
        tshark.sendintr()
50
51
    def testBasic( self ):
52
        "Test basic CLI commands (help, nodes, net, dump)"
53
        p = pexpect.spawn( 'mn' )
54
        p.expect( self.prompt )
55
        # help command
56
        p.sendline( 'help' )
57
        index = p.expect( [ 'commands', self.prompt ] )
58
        self.assertEqual( index, 0, 'No output for "help" command')
59
        # nodes command
60
        p.sendline( 'nodes' )
61 1471da95 Bob Lantz
        p.expect( r'([chs]\d ?){4}' )
62 895ff6f4 Brian O'Connor
        nodes = p.match.group( 0 ).split()
63
        self.assertEqual( len( nodes ), 4, 'No nodes in "nodes" command')
64
        p.expect( self.prompt )
65
        # net command
66
        p.sendline( 'net' )
67
        expected = [ x for x in nodes ]
68
        while len( expected ) > 0:
69
            index = p.expect( expected )
70
            node = p.match.group( 0 )
71
            expected.remove( node )
72
            p.expect( '\n' )
73
        self.assertEqual( len( expected ), 0, '"nodes" and "net" differ')
74
        p.expect( self.prompt )
75
        # dump command
76
        p.sendline( 'dump' )
77 1471da95 Bob Lantz
        expected = [ r'<\w+ (%s)' % n for n in nodes ]
78 895ff6f4 Brian O'Connor
        actual = []
79
        for _ in nodes:
80
            index = p.expect( expected )
81
            node = p.match.group( 1 )
82
            actual.append( node )
83
            p.expect( '\n' )
84 18aab5b7 Bob Lantz
        self.assertEqual( actual.sort(), nodes.sort(),
85
                          '"nodes" and "dump" differ' )
86 895ff6f4 Brian O'Connor
        p.expect( self.prompt )
87
        p.sendline( 'exit' )
88
        p.wait()
89
90
    def testHostCommands( self ):
91
        "Test ifconfig and ps on h1 and s1"
92
        p = pexpect.spawn( 'mn' )
93
        p.expect( self.prompt )
94
        interfaces = [ 'h1-eth0', 's1-eth1', '[^-]eth0', 'lo', self.prompt ]
95
        # h1 ifconfig
96
        p.sendline( 'h1 ifconfig -a' )
97
        ifcount = 0
98
        while True:
99
            index = p.expect( interfaces )
100
            if index == 0 or index == 3:
101
                ifcount += 1
102
            elif index == 1:
103
                self.fail( 's1 interface displayed in "h1 ifconfig"' )
104
            elif index == 2:
105
                self.fail( 'eth0 displayed in "h1 ifconfig"' )
106
            else:
107
                break
108
        self.assertEqual( ifcount, 2, 'Missing interfaces on h1')
109
        # s1 ifconfig
110
        p.sendline( 's1 ifconfig -a' )
111
        ifcount = 0
112
        while True:
113
            index = p.expect( interfaces )
114
            if index == 0:
115
                self.fail( 'h1 interface displayed in "s1 ifconfig"' )
116
            elif index == 1 or index == 2 or index == 3:
117
                ifcount += 1
118
            else:
119
                break
120
        self.assertEqual( ifcount, 3, 'Missing interfaces on s1')
121
        # h1 ps
122 e3ab3fc2 cody burkard
        p.sendline( "h1 ps -a | egrep -v 'ps|grep'" )
123 895ff6f4 Brian O'Connor
        p.expect( self.prompt )
124
        h1Output = p.before
125
        # s1 ps
126 e3ab3fc2 cody burkard
        p.sendline( "s1 ps -a | egrep -v 'ps|grep'" )
127 895ff6f4 Brian O'Connor
        p.expect( self.prompt )
128
        s1Output = p.before
129
        # strip command from ps output
130
        h1Output = h1Output.split( '\n', 1 )[ 1 ]
131
        s1Output = s1Output.split( '\n', 1 )[ 1 ]
132
        self.assertEqual( h1Output, s1Output, 'h1 and s1 "ps" output differs')
133
        p.sendline( 'exit' )
134
        p.wait()
135
136
    def testConnectivity( self ):
137
        "Test ping and pingall"
138
        p = pexpect.spawn( 'mn' )
139
        p.expect( self.prompt )
140
        p.sendline( 'h1 ping -c 1 h2' )
141
        p.expect( '1 packets transmitted, 1 received' )
142
        p.expect( self.prompt )
143
        p.sendline( 'pingall' )
144
        p.expect( '0% dropped' )
145
        p.expect( self.prompt )
146
        p.sendline( 'exit' )
147
        p.wait()
148
149
    def testSimpleHTTP( self ):
150
        "Start an HTTP server on h1 and wget from h2"
151
        p = pexpect.spawn( 'mn' )
152
        p.expect( self.prompt )
153
        p.sendline( 'h1 python -m SimpleHTTPServer 80 &' )
154
        p.expect( self.prompt )
155
        p.sendline( ' h2 wget -O - h1' )
156
        p.expect( '200 OK' )
157
        p.expect( self.prompt )
158
        p.sendline( 'h1 kill %python' )
159
        p.expect( self.prompt )
160
        p.sendline( 'exit' )
161
        p.wait()
162
163
    # PART 2
164
    def testRegressionRun( self ):
165
        "Test pingpair (0% drop) and iperf (bw > 0) regression tests"
166
        # test pingpair
167
        p = pexpect.spawn( 'mn --test pingpair' )
168
        p.expect( '0% dropped' )
169
        p.expect( pexpect.EOF )
170
        # test iperf
171
        p = pexpect.spawn( 'mn --test iperf' )
172 1471da95 Bob Lantz
        p.expect( r"Results: \['([\d\.]+) .bits/sec'," )
173 895ff6f4 Brian O'Connor
        bw = float( p.match.group( 1 ) )
174
        self.assertTrue( bw > 0 )
175
        p.expect( pexpect.EOF )
176
177
    def testTopoChange( self ):
178
        "Test pingall on single,3 and linear,4 topos"
179
        # testing single,3
180
        p = pexpect.spawn( 'mn --test pingall --topo single,3' )
181 1471da95 Bob Lantz
        p.expect( r'(\d+)/(\d+) received')
182 895ff6f4 Brian O'Connor
        received = int( p.match.group( 1 ) )
183
        sent = int( p.match.group( 2 ) )
184
        self.assertEqual( sent, 6, 'Wrong number of pings sent in single,3' )
185
        self.assertEqual( sent, received, 'Dropped packets in single,3')
186
        p.expect( pexpect.EOF )
187
        # testing linear,4
188
        p = pexpect.spawn( 'mn --test pingall --topo linear,4' )
189 1471da95 Bob Lantz
        p.expect( r'(\d+)/(\d+) received')
190 895ff6f4 Brian O'Connor
        received = int( p.match.group( 1 ) )
191
        sent = int( p.match.group( 2 ) )
192
        self.assertEqual( sent, 12, 'Wrong number of pings sent in linear,4' )
193
        self.assertEqual( sent, received, 'Dropped packets in linear,4')
194
        p.expect( pexpect.EOF )
195
196
    def testLinkChange( self ):
197
        "Test TCLink bw and delay"
198
        p = pexpect.spawn( 'mn --link tc,bw=10,delay=10ms' )
199
        # test bw
200
        p.expect( self.prompt )
201
        p.sendline( 'iperf' )
202 1471da95 Bob Lantz
        p.expect( r"Results: \['([\d\.]+) Mbits/sec'," )
203 895ff6f4 Brian O'Connor
        bw = float( p.match.group( 1 ) )
204
        self.assertTrue( bw < 10.1, 'Bandwidth > 10 Mb/s')
205
        self.assertTrue( bw > 9.0, 'Bandwidth < 9 Mb/s')
206
        p.expect( self.prompt )
207
        # test delay
208
        p.sendline( 'h1 ping -c 4 h2' )
209 18aab5b7 Bob Lantz
        p.expect( r'rtt min/avg/max/mdev = '
210
                  r'([\d\.]+)/([\d\.]+)/([\d\.]+)/([\d\.]+) ms' )
211 895ff6f4 Brian O'Connor
        delay = float( p.match.group( 2 ) )
212
        self.assertTrue( delay > 40, 'Delay < 40ms' )
213
        self.assertTrue( delay < 45, 'Delay > 40ms' )
214
        p.expect( self.prompt )
215
        p.sendline( 'exit' )
216
        p.wait()
217
218
    def testVerbosity( self ):
219
        "Test debug and output verbosity"
220
        # test output
221
        p = pexpect.spawn( 'mn -v output' )
222
        p.expect( self.prompt )
223
        self.assertEqual( len( p.before ), 0, 'Too much output for "output"' )
224
        p.sendline( 'exit' )
225
        p.wait()
226
        # test debug
227
        p = pexpect.spawn( 'mn -v debug --test none' )
228
        p.expect( pexpect.EOF )
229
        lines = p.before.split( '\n' )
230 e3ab3fc2 cody burkard
        self.assertTrue( len( lines ) > 70, "Debug output is too short" )
231 895ff6f4 Brian O'Connor
232
    def testCustomTopo( self ):
233
        "Start Mininet using a custom topo, then run pingall"
234 18aab5b7 Bob Lantz
        # Satisfy pylint
235
        assert self
236 895ff6f4 Brian O'Connor
        custom = os.path.dirname( os.path.realpath( __file__ ) )
237
        custom = os.path.join( custom, '../../custom/topo-2sw-2host.py' )
238
        custom = os.path.normpath( custom )
239 18aab5b7 Bob Lantz
        p = pexpect.spawn(
240
            'mn --custom %s --topo mytopo --test pingall' % custom )
241 895ff6f4 Brian O'Connor
        p.expect( '0% dropped' )
242
        p.expect( pexpect.EOF )
243
244
    def testStaticMAC( self ):
245
        "Verify that MACs are set to easy to read numbers"
246
        p = pexpect.spawn( 'mn --mac' )
247
        p.expect( self.prompt )
248
        for i in range( 1, 3 ):
249
            p.sendline( 'h%d ifconfig' % i )
250
            p.expect( 'HWaddr 00:00:00:00:00:0%d' % i )
251
            p.expect( self.prompt )
252
253
    def testSwitches( self ):
254
        "Run iperf test using user and ovsk switches"
255
        switches = [ 'user', 'ovsk' ]
256
        for sw in switches:
257
            p = pexpect.spawn( 'mn --switch %s --test iperf' % sw )
258 1471da95 Bob Lantz
            p.expect( r"Results: \['([\d\.]+) .bits/sec'," )
259 895ff6f4 Brian O'Connor
            bw = float( p.match.group( 1 ) )
260
            self.assertTrue( bw > 0 )
261
            p.expect( pexpect.EOF )
262
263
    def testBenchmark( self ):
264
        "Run benchmark and verify that it takes less than 2 seconds"
265
        p = pexpect.spawn( 'mn --test none' )
266 1471da95 Bob Lantz
        p.expect( r'completed in ([\d\.]+) seconds' )
267 895ff6f4 Brian O'Connor
        time = float( p.match.group( 1 ) )
268
        self.assertTrue( time < 2, 'Benchmark takes more than 2 seconds' )
269
270
    def testOwnNamespace( self ):
271
        "Test running user switch in its own namespace"
272
        p = pexpect.spawn( 'mn --innamespace --switch user' )
273
        p.expect( self.prompt )
274
        interfaces = [ 'h1-eth0', 's1-eth1', '[^-]eth0', 'lo', self.prompt ]
275
        p.sendline( 's1 ifconfig -a' )
276
        ifcount = 0
277
        while True:
278
            index = p.expect( interfaces )
279
            if index == 1 or index == 3:
280
                ifcount += 1
281
            elif index == 0:
282
                self.fail( 'h1 interface displayed in "s1 ifconfig"' )
283
            elif index == 2:
284
                self.fail( 'eth0 displayed in "s1 ifconfig"' )
285
            else:
286
                break
287
        self.assertEqual( ifcount, 2, 'Missing interfaces on s1' )
288
        # verify that all hosts a reachable
289
        p.sendline( 'pingall' )
290 1471da95 Bob Lantz
        p.expect( r'(\d+)% dropped' )
291 895ff6f4 Brian O'Connor
        dropped = int( p.match.group( 1 ) )
292
        self.assertEqual( dropped, 0, 'pingall failed')
293
        p.expect( self.prompt )
294
        p.sendline( 'exit' )
295
        p.wait()
296
297
    # PART 3
298
    def testPythonInterpreter( self ):
299
        "Test py and px by checking IP for h1 and adding h3"
300
        p = pexpect.spawn( 'mn' )
301
        p.expect( self.prompt )
302
        # test host IP
303
        p.sendline( 'py h1.IP()' )
304
        p.expect( '10.0.0.1' )
305
        p.expect( self.prompt )
306
        # test adding host
307
        p.sendline( "px net.addHost('h3')" )
308
        p.expect( self.prompt )
309
        p.sendline( "px net.addLink(s1, h3)" )
310
        p.expect( self.prompt )
311
        p.sendline( 'net' )
312
        p.expect( 'h3' )
313
        p.expect( self.prompt )
314
        p.sendline( 'py h3.MAC()' )
315
        p.expect( '([a-f0-9]{2}:?){6}' )
316
        p.expect( self.prompt )
317
        p.sendline( 'exit' )
318
        p.wait()
319
320
    def testLink( self ):
321
        "Test link CLI command using ping"
322
        p = pexpect.spawn( 'mn' )
323
        p.expect( self.prompt )
324
        p.sendline( 'link s1 h1 down' )
325
        p.expect( self.prompt )
326
        p.sendline( 'h1 ping -c 1 h2' )
327
        p.expect( 'unreachable' )
328
        p.expect( self.prompt )
329
        p.sendline( 'link s1 h1 up' )
330
        p.expect( self.prompt )
331
        p.sendline( 'h1 ping -c 1 h2' )
332
        p.expect( '0% packet loss' )
333
        p.expect( self.prompt )
334
        p.sendline( 'exit' )
335
        p.wait()
336
337 fc2a8fd5 Brian O'Connor
    @unittest.skipUnless( os.path.exists( '/tmp/pox' ) or
338
                          '1 received' in quietRun( 'ping -c 1 github.com' ),
339 895ff6f4 Brian O'Connor
                          'Github is not reachable; cannot download Pox' )
340
    def testRemoteController( self ):
341
        "Test Mininet using Pox controller"
342 18aab5b7 Bob Lantz
        # Satisfy pylint
343
        assert self
344 fc2a8fd5 Brian O'Connor
        if not os.path.exists( '/tmp/pox' ):
345 18aab5b7 Bob Lantz
            p = pexpect.spawn(
346
                'git clone https://github.com/noxrepo/pox.git /tmp/pox' )
347 fc2a8fd5 Brian O'Connor
            p.expect( pexpect.EOF )
348 895ff6f4 Brian O'Connor
        pox = pexpect.spawn( '/tmp/pox/pox.py forwarding.l2_learning' )
349 18aab5b7 Bob Lantz
        net = pexpect.spawn(
350
            'mn --controller=remote,ip=127.0.0.1,port=6633 --test pingall' )
351 895ff6f4 Brian O'Connor
        net.expect( '0% dropped' )
352
        net.expect( pexpect.EOF )
353
        pox.sendintr()
354
        pox.wait()
355
356 e3ab3fc2 cody burkard
357 895ff6f4 Brian O'Connor
if __name__ == '__main__':
358 e3ab3fc2 cody burkard
    unittest.main()