Merge pull request #143 from stevenvanrossem/master
[osm/vim-emu.git] / src / emuvim / test / unittests / test_emulator.py
1 """
2 Copyright (c) 2015 SONATA-NFV
3 ALL RIGHTS RESERVED.
4
5 Licensed under the Apache License, Version 2.0 (the "License");
6 you may not use this file except in compliance with the License.
7 You may obtain a copy of the License at
8
9 http://www.apache.org/licenses/LICENSE-2.0
10
11 Unless required by applicable law or agreed to in writing, software
12 distributed under the License is distributed on an "AS IS" BASIS,
13 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 See the License for the specific language governing permissions and
15 limitations under the License.
16
17 Neither the name of the SONATA-NFV [, ANY ADDITIONAL AFFILIATION]
18 nor the names of its contributors may be used to endorse or promote
19 products derived from this software without specific prior written
20 permission.
21
22 This work has been performed in the framework of the SONATA project,
23 funded by the European Commission under Grant number 671517 through
24 the Horizon 2020 and 5G-PPP programmes. The authors would like to
25 acknowledge the contributions of their colleagues of the SONATA
26 partner consortium (www.sonata-nfv.eu).
27 """
28 """
29 Test suite to automatically test emulator functionalities.
30 Directly interacts with the emulator through the Mininet-like
31 Python API.
32
33 Does not test API endpoints. This is done in separated test suites.
34 """
35
36 import time
37 import unittest
38 from emuvim.dcemulator.node import EmulatorCompute
39 from emuvim.test.base import SimpleTestTopology
40 from mininet.node import RemoteController
41
42
43 #@unittest.skip("disabled topology tests for development")
44 class testEmulatorTopology( SimpleTestTopology ):
45 """
46 Tests to check the topology API of the emulator.
47 """
48
49 def testSingleDatacenter(self):
50 """
51 Create a single data center and add check if its switch is up
52 by using manually added hosts. Tests especially the
53 data center specific addLink method.
54 """
55 # create network
56 self.createNet(nswitches=0, ndatacenter=1, nhosts=2, ndockers=0)
57 # setup links
58 self.net.addLink(self.dc[0], self.h[0])
59 self.net.addLink(self.h[1], self.dc[0])
60 # start Mininet network
61 self.startNet()
62 # check number of running nodes
63 self.assertTrue(len(self.getContainernetContainers()) == 0)
64 self.assertTrue(len(self.net.hosts) == 2)
65 self.assertTrue(len(self.net.switches) == 1)
66 # check connectivity by using ping
67 self.assertTrue(self.net.ping([self.h[0], self.h[1]]) <= 0.0)
68 # stop Mininet network
69 self.stopNet()
70
71 #@unittest.skip("disabled to test if CI fails because this is the first test.")
72 def testMultipleDatacenterDirect(self):
73 """
74 Create a two data centers and interconnect them.
75 """
76 # create network
77 self.createNet(nswitches=0, ndatacenter=2, nhosts=2, ndockers=0)
78 # setup links
79 self.net.addLink(self.dc[0], self.h[0])
80 self.net.addLink(self.h[1], self.dc[1])
81 self.net.addLink(self.dc[0], self.dc[1])
82 # start Mininet network
83 self.startNet()
84 # check number of running nodes
85 self.assertTrue(len(self.getContainernetContainers()) == 0)
86 self.assertTrue(len(self.net.hosts) == 2)
87 self.assertTrue(len(self.net.switches) == 2)
88 # check connectivity by using ping
89 self.assertTrue(self.net.ping([self.h[0], self.h[1]]) <= 0.0)
90 # stop Mininet network
91 self.stopNet()
92
93 def testMultipleDatacenterWithIntermediateSwitches(self):
94 """
95 Create a two data centers and interconnect them with additional
96 switches between them.
97 """
98 # create network
99 self.createNet(
100 nswitches=3, ndatacenter=2, nhosts=2, ndockers=0,
101 autolinkswitches=True)
102 # setup links
103 self.net.addLink(self.dc[0], self.h[0])
104 self.net.addLink(self.h[1], self.dc[1])
105 self.net.addLink(self.dc[0], self.s[0])
106 self.net.addLink(self.s[2], self.dc[1])
107 # start Mininet network
108 self.startNet()
109 # check number of running nodes
110 self.assertTrue(len(self.getContainernetContainers()) == 0)
111 self.assertTrue(len(self.net.hosts) == 2)
112 self.assertTrue(len(self.net.switches) == 5)
113 # check connectivity by using ping
114 self.assertTrue(self.net.ping([self.h[0], self.h[1]]) <= 0.0)
115 # stop Mininet network
116 self.stopNet()
117
118 class testEmulatorNetworking( SimpleTestTopology ):
119
120 def testSDNChainingSingleService(self):
121 """
122 Create a two data centers and interconnect them with additional
123 switches between them.
124 Uses Ryu SDN controller.
125 Connect the Docker hosts to different datacenters and setup the links between.
126 """
127 # create network
128 self.createNet(
129 nswitches=3, ndatacenter=2, nhosts=0, ndockers=0,
130 autolinkswitches=True,
131 controller=RemoteController,
132 enable_learning=False)
133 # setup links
134 self.net.addLink(self.dc[0], self.s[0])
135 self.net.addLink(self.s[2], self.dc[1])
136 # start Mininet network
137 self.startNet()
138
139 # add compute resources
140 vnf1 = self.dc[0].startCompute("vnf1", network=[{'id':'intf1', 'ip':'10.0.10.1/24'}])
141 vnf2 = self.dc[1].startCompute("vnf2", network=[{'id':'intf2', 'ip':'10.0.10.2/24'}])
142 # check number of running nodes
143 self.assertTrue(len(self.getContainernetContainers()) == 2)
144 self.assertTrue(len(self.net.hosts) == 2)
145 self.assertTrue(len(self.net.switches) == 5)
146 # check status
147 # check get status
148 s1 = self.dc[0].containers.get("vnf1").getStatus()
149 self.assertTrue(s1["name"] == "vnf1")
150 self.assertTrue(s1["state"]["Running"])
151 self.assertTrue(s1["network"][0]['intf_name'] == 'intf1')
152 self.assertTrue(s1["network"][0]['ip'] == '10.0.10.1')
153
154 s2 = self.dc[1].containers.get("vnf2").getStatus()
155 self.assertTrue(s2["name"] == "vnf2")
156 self.assertTrue(s2["state"]["Running"])
157 self.assertTrue(s2["network"][0]['intf_name'] == 'intf2')
158 self.assertTrue(s2["network"][0]['ip'] == '10.0.10.2')
159
160 # should be not not yet connected
161 self.assertTrue(self.net.ping([vnf1, vnf2]) > 0.0)
162 # setup links
163 self.net.setChain('vnf1', 'vnf2', 'intf1', 'intf2', bidirectional=True, cmd='add-flow')
164 # check connectivity by using ping
165 self.assertTrue(self.net.ping([vnf1, vnf2]) <= 0.0)
166 # stop Mininet network
167 self.stopNet()
168
169 def testSDNChainingMultiService(self):
170 """
171 Create a two data centers and interconnect them with additional
172 switches between them.
173 Uses Ryu SDN controller.
174 Setup 2 services and setup isolated paths between them
175 Delete only the first service, and check that other one still works
176 """
177 # create network
178 self.createNet(
179 nswitches=3, ndatacenter=2, nhosts=0, ndockers=0,
180 autolinkswitches=True,
181 controller=RemoteController,
182 enable_learning=False)
183 # setup links
184 self.net.addLink(self.dc[0], self.s[0])
185 self.net.addLink(self.s[2], self.dc[1])
186 # start Mininet network
187 self.startNet()
188
189 ## First Service
190 # add compute resources
191 vnf1 = self.dc[0].startCompute("vnf1", network=[{'id': 'intf1', 'ip': '10.0.10.1/24'}])
192 vnf2 = self.dc[1].startCompute("vnf2", network=[{'id': 'intf2', 'ip': '10.0.10.2/24'}])
193 # setup links
194 self.net.setChain('vnf1', 'vnf2', 'intf1', 'intf2', bidirectional=True, cmd='add-flow', cookie=1)
195 # check connectivity by using ping
196 self.assertTrue(self.net.ping([vnf1, vnf2]) <= 0.0)
197
198 ## Second Service
199 # add compute resources
200 vnf11 = self.dc[0].startCompute("vnf11", network=[{'id': 'intf1', 'ip': '10.0.20.1/24'}])
201 vnf22 = self.dc[1].startCompute("vnf22", network=[{'id': 'intf2', 'ip': '10.0.20.2/24'}])
202
203 # check number of running nodes
204 self.assertTrue(len(self.getContainernetContainers()) == 4)
205 self.assertTrue(len(self.net.hosts) == 4)
206 self.assertTrue(len(self.net.switches) == 5)
207
208 # setup links
209 self.net.setChain('vnf11', 'vnf22', 'intf1', 'intf2', bidirectional=True, cmd='add-flow', cookie=2)
210 # check connectivity by using ping
211 self.assertTrue(self.net.ping([vnf11, vnf22]) <= 0.0)
212 # check first service cannot ping second service
213 self.assertTrue(self.net.ping([vnf1, vnf22]) > 0.0)
214 self.assertTrue(self.net.ping([vnf2, vnf11]) > 0.0)
215
216 # delete the first service chain
217 self.net.setChain('vnf1', 'vnf2', 'intf1', 'intf2', bidirectional=True, cmd='del-flows', cookie=1)
218 # check connectivity of first service is down
219 self.assertTrue(self.net.ping([vnf1, vnf2]) > 0.0)
220 #time.sleep(100)
221 # check connectivity of second service is still up
222 self.assertTrue(self.net.ping([vnf11, vnf22]) <= 0.0)
223
224 # stop Mininet network
225 self.stopNet()
226
227 #@unittest.skip("disabled compute tests for development")
228 class testEmulatorCompute( SimpleTestTopology ):
229 """
230 Tests to check the emulator's API to add and remove
231 compute resources at runtime.
232 """
233
234 def testAddSingleComputeSingleDC(self):
235 """
236 Adds a single compute instance to
237 a single DC and checks its connectivity with a
238 manually added host.
239 """
240 # create network
241 self.createNet(nswitches=0, ndatacenter=1, nhosts=1, ndockers=0)
242 # setup links
243 self.net.addLink(self.dc[0], self.h[0])
244 # start Mininet network
245 self.startNet()
246 # add compute resources
247 vnf1 = self.dc[0].startCompute("vnf1")
248 # check number of running nodes
249 self.assertTrue(len(self.getContainernetContainers()) == 1)
250 self.assertTrue(len(self.net.hosts) == 2)
251 self.assertTrue(len(self.net.switches) == 1)
252 # check compute list result
253 self.assertTrue(len(self.dc[0].listCompute()) == 1)
254 self.assertTrue(isinstance(self.dc[0].listCompute()[0], EmulatorCompute))
255 self.assertTrue(self.dc[0].listCompute()[0].name == "vnf1")
256 # check connectivity by using ping
257 self.assertTrue(self.net.ping([self.h[0], vnf1]) <= 0.0)
258 # stop Mininet network
259 self.stopNet()
260
261 def testRemoveSingleComputeSingleDC(self):
262 """
263 Test stop method for compute instances.
264 Check that the instance is really removed.
265 """
266 # create network
267 self.createNet(nswitches=0, ndatacenter=1, nhosts=1, ndockers=0)
268 # setup links
269 self.net.addLink(self.dc[0], self.h[0])
270 # start Mininet network
271 self.startNet()
272 # add compute resources
273 vnf1 = self.dc[0].startCompute("vnf1")
274 # check number of running nodes
275 self.assertTrue(len(self.getContainernetContainers()) == 1)
276 self.assertTrue(len(self.net.hosts) == 2)
277 self.assertTrue(len(self.net.switches) == 1)
278 # check compute list result
279 self.assertTrue(len(self.dc[0].listCompute()) == 1)
280 # check connectivity by using ping
281 self.assertTrue(self.net.ping([self.h[0], vnf1]) <= 0.0)
282 # remove compute resources
283 self.dc[0].stopCompute("vnf1")
284 # check number of running nodes
285 self.assertTrue(len(self.getContainernetContainers()) == 0)
286 self.assertTrue(len(self.net.hosts) == 1)
287 self.assertTrue(len(self.net.switches) == 1)
288 # check compute list result
289 self.assertTrue(len(self.dc[0].listCompute()) == 0)
290 # stop Mininet network
291 self.stopNet()
292
293 def testGetStatusSingleComputeSingleDC(self):
294 """
295 Check if the getStatus functionality of EmulatorCompute
296 objects works well.
297 """
298 # create network
299 self.createNet(nswitches=0, ndatacenter=1, nhosts=1, ndockers=0)
300 # setup links
301 self.net.addLink(self.dc[0], self.h[0])
302 # start Mininet network
303 self.startNet()
304 # add compute resources
305 vnf1 = self.dc[0].startCompute("vnf1")
306 # check number of running nodes
307 self.assertTrue(len(self.getContainernetContainers()) == 1)
308 self.assertTrue(len(self.net.hosts) == 2)
309 self.assertTrue(len(self.net.switches) == 1)
310 # check compute list result
311 self.assertTrue(len(self.dc[0].listCompute()) == 1)
312 self.assertTrue(isinstance(self.dc[0].listCompute()[0], EmulatorCompute))
313 self.assertTrue(self.dc[0].listCompute()[0].name == "vnf1")
314 # check connectivity by using ping
315 self.assertTrue(self.net.ping([self.h[0], vnf1]) <= 0.0)
316 # check get status
317 s = self.dc[0].containers.get("vnf1").getStatus()
318 self.assertTrue(s["name"] == "vnf1")
319 self.assertTrue(s["state"]["Running"])
320 # stop Mininet network
321 self.stopNet()
322
323 def testConnectivityMultiDC(self):
324 """
325 Test if compute instances started in different data centers
326 are able to talk to each other.
327 """
328 # create network
329 self.createNet(
330 nswitches=3, ndatacenter=2, nhosts=0, ndockers=0,
331 autolinkswitches=True)
332 # setup links
333 self.net.addLink(self.dc[0], self.s[0])
334 self.net.addLink(self.dc[1], self.s[2])
335 # start Mininet network
336 self.startNet()
337 # add compute resources
338 vnf1 = self.dc[0].startCompute("vnf1")
339 vnf2 = self.dc[1].startCompute("vnf2")
340 # check number of running nodes
341 self.assertTrue(len(self.getContainernetContainers()) == 2)
342 self.assertTrue(len(self.net.hosts) == 2)
343 self.assertTrue(len(self.net.switches) == 5)
344 # check compute list result
345 self.assertTrue(len(self.dc[0].listCompute()) == 1)
346 self.assertTrue(len(self.dc[1].listCompute()) == 1)
347 # check connectivity by using ping
348 self.assertTrue(self.net.ping([vnf1, vnf2]) <= 0.0)
349 # stop Mininet network
350 self.stopNet()
351
352 def testInterleavedAddRemoveMultiDC(self):
353 """
354 Test multiple, interleaved add and remove operations and ensure
355 that always all expected compute instances are reachable.
356 """
357 # create network
358 self.createNet(
359 nswitches=3, ndatacenter=2, nhosts=0, ndockers=0,
360 autolinkswitches=True)
361 # setup links
362 self.net.addLink(self.dc[0], self.s[0])
363 self.net.addLink(self.dc[1], self.s[2])
364 # start Mininet network
365 self.startNet()
366 # add compute resources
367 vnf1 = self.dc[0].startCompute("vnf1")
368 vnf2 = self.dc[1].startCompute("vnf2")
369 # check number of running nodes
370 self.assertTrue(len(self.getContainernetContainers()) == 2)
371 self.assertTrue(len(self.net.hosts) == 2)
372 self.assertTrue(len(self.net.switches) == 5)
373 # check compute list result
374 self.assertTrue(len(self.dc[0].listCompute()) == 1)
375 self.assertTrue(len(self.dc[1].listCompute()) == 1)
376 # check connectivity by using ping
377 self.assertTrue(self.net.ping([vnf1, vnf2]) <= 0.0)
378 # remove compute resources
379 self.dc[0].stopCompute("vnf1")
380 # check number of running nodes
381 self.assertTrue(len(self.getContainernetContainers()) == 1)
382 self.assertTrue(len(self.net.hosts) == 1)
383 self.assertTrue(len(self.net.switches) == 5)
384 # check compute list result
385 self.assertTrue(len(self.dc[0].listCompute()) == 0)
386 self.assertTrue(len(self.dc[1].listCompute()) == 1)
387 # add compute resources
388 vnf3 = self.dc[0].startCompute("vnf3")
389 vnf4 = self.dc[0].startCompute("vnf4")
390 # check compute list result
391 self.assertTrue(len(self.dc[0].listCompute()) == 2)
392 self.assertTrue(len(self.dc[1].listCompute()) == 1)
393 self.assertTrue(self.net.ping([vnf3, vnf2]) <= 0.0)
394 self.assertTrue(self.net.ping([vnf4, vnf2]) <= 0.0)
395 # remove compute resources
396 self.dc[0].stopCompute("vnf3")
397 self.dc[0].stopCompute("vnf4")
398 self.dc[1].stopCompute("vnf2")
399 # check compute list result
400 self.assertTrue(len(self.dc[0].listCompute()) == 0)
401 self.assertTrue(len(self.dc[1].listCompute()) == 0)
402 # stop Mininet network
403 self.stopNet()
404
405 if __name__ == '__main__':
406 unittest.main()