Statistics
| Branch: | Tag: | Revision:

mininet / mininet / test / test_walkthrough.py @ 18aab5b7

History | View | Annotate | Download (12.6 KB)

1
#!/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
import re
13
from mininet.util import quietRun
14
from distutils.version import StrictVersion
15

    
16
def tsharkVersion():
17
    "Return tshark version"
18
    versionStr = quietRun( 'tshark -v' )
19
    versionMatch = re.findall( r'TShark \d+.\d+.\d+', versionStr )[0]
20
    return versionMatch.split()[ 1 ]
21

    
22
# pylint doesn't understand pexpect.match, unfortunately!
23
# pylint:disable=maybe-no-member
24

    
25
class testWalkthrough( unittest.TestCase ):
26
    "Test Mininet walkthrough"
27

    
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
        # Satisfy pylint
40
        assert self
41
        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
        tshark.expect( [ 'Capturing on lo', "Capturing on 'Loopback'" ] )
46
        mn = pexpect.spawn( 'mn --test pingall' )
47
        mn.expect( '0% dropped' )
48
        tshark.expect( [ '74 Hello', '74 of_hello', '74 Type: OFPT_HELLO' ] )
49
        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
        p.expect( r'([chs]\d ?){4}' )
62
        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
        expected = [ r'<\w+ (%s)' % n for n in nodes ]
78
        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
        self.assertEqual( actual.sort(), nodes.sort(),
85
                          '"nodes" and "dump" differ' )
86
        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
        p.sendline( "h1 ps -a | egrep -v 'ps|grep'" )
123
        p.expect( self.prompt )
124
        h1Output = p.before
125
        # s1 ps
126
        p.sendline( "s1 ps -a | egrep -v 'ps|grep'" )
127
        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
        p.expect( r"Results: \['([\d\.]+) .bits/sec'," )
173
        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
        p.expect( r'(\d+)/(\d+) received')
182
        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
        p.expect( r'(\d+)/(\d+) received')
190
        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
        p.expect( r"Results: \['([\d\.]+) Mbits/sec'," )
203
        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
        p.expect( r'rtt min/avg/max/mdev = '
210
                  r'([\d\.]+)/([\d\.]+)/([\d\.]+)/([\d\.]+) ms' )
211
        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
        self.assertTrue( len( lines ) > 70, "Debug output is too short" )
231

    
232
    def testCustomTopo( self ):
233
        "Start Mininet using a custom topo, then run pingall"
234
        # Satisfy pylint
235
        assert self
236
        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
        p = pexpect.spawn(
240
            'mn --custom %s --topo mytopo --test pingall' % custom )
241
        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
            p.expect( r"Results: \['([\d\.]+) .bits/sec'," )
259
            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
        p.expect( r'completed in ([\d\.]+) seconds' )
267
        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
        p.expect( r'(\d+)% dropped' )
291
        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
    @unittest.skipUnless( os.path.exists( '/tmp/pox' ) or
338
                          '1 received' in quietRun( 'ping -c 1 github.com' ),
339
                          'Github is not reachable; cannot download Pox' )
340
    def testRemoteController( self ):
341
        "Test Mininet using Pox controller"
342
        # Satisfy pylint
343
        assert self
344
        if not os.path.exists( '/tmp/pox' ):
345
            p = pexpect.spawn(
346
                'git clone https://github.com/noxrepo/pox.git /tmp/pox' )
347
            p.expect( pexpect.EOF )
348
        pox = pexpect.spawn( '/tmp/pox/pox.py forwarding.l2_learning' )
349
        net = pexpect.spawn(
350
            'mn --controller=remote,ip=127.0.0.1,port=6633 --test pingall' )
351
        net.expect( '0% dropped' )
352
        net.expect( pexpect.EOF )
353
        pox.sendintr()
354
        pox.wait()
355

    
356

    
357
if __name__ == '__main__':
358
    unittest.main()