Passed
Pull Request — master (#107)
by
unknown
02:42
created

build.tests.unit.test_main   A

Complexity

Total Complexity 22

Size/Duplication

Total Lines 991
Duplicated Lines 18.97 %

Test Coverage

Coverage 100%

Importance

Changes 0
Metric Value
wmc 22
eloc 680
dl 188
loc 991
ccs 287
cts 287
cp 1
rs 9.92
c 0
b 0
f 0

21 Methods

Rating   Name   Duplication   Size   Complexity  
A TestMain.setup_method() 0 26 2
A TestMain.test_trace_step() 0 49 1
A TestMain.test_has_loop__fail() 0 29 1
A TestMain.test_tracepath() 0 33 1
A TestMain.test_trace_step__no_flow() 0 24 1
A TestMain.test_has_loop() 0 47 1
A TestMain.test_tracepath_loop() 0 22 1
A TestMain.test_trace_step__no_endpoint() 0 36 1
B TestMain.test_traces() 0 77 1
B TestMain.test_get_traces_untagged() 0 83 1
B TestMain.test_do_match() 0 72 1
B TestMain.test_match_and_apply() 0 69 1
A TestMain.test_traces_fail() 0 16 1
A TestMain.test_get_traces() 46 46 1
B TestMain.test_trace_instructions() 51 51 1
A TestMain.test_match_flows() 0 12 1
A TestMain.test_trace_fail() 0 16 1
B TestMain.test_get_traces_any() 0 91 1
A TestMain.test_trace() 46 46 1
B TestMain.test_traces_no_action() 0 60 1
A TestMain.test_traces_with_loop() 45 45 1

How to fix   Duplicated Code   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

1
"""Module to test the main napp file."""
2 1
import pytest
3 1
from unittest.mock import patch, MagicMock
4
5 1
from kytos.core.interface import Interface
6 1
from kytos.lib.helpers import (
7
    get_interface_mock,
8
    get_switch_mock,
9
    get_controller_mock,
10
    get_link_mock,
11
    get_test_client,
12
)
13 1
from kytos.core.rest_api import HTTPException
14
15
16
# pylint: disable=too-many-public-methods, too-many-lines
17 1
class TestMain:
18
    """Test the Main class."""
19
20 1
    def setup_method(self):
21
        """Execute steps before each tests."""
22
        # The decorator run_on_thread is patched, so methods that listen
23
        # for events do not run on threads while tested.
24
        # Decorators have to be patched before the methods that are
25
        # decorated with them are imported.
26 1
        patch("kytos.core.helpers.run_on_thread", lambda x: x).start()
27
        # pylint: disable=import-outside-toplevel
28 1
        from napps.amlight.sdntrace_cp.main import Main
29
30 1
        controller = get_controller_mock()
31 1
        self.napp = Main(controller)
32
33 1
        sw1 = get_switch_mock("00:00:00:00:00:00:00:01", 0x04)
34 1
        intf_sw1 = get_interface_mock("eth1", 1, sw1)
35 1
        intf_sw1.link = None
36 1
        sw1.get_interface_by_port_no.return_value = intf_sw1
37 1
        sw2 = get_switch_mock("00:00:00:00:00:00:00:02", 0x04)
38 1
        intf_sw2 = get_interface_mock("eth1", 1, sw2)
39 1
        intf_sw2.link = None
40 1
        sw2.get_interface_by_port_no.return_value = intf_sw2
41 1
        self.napp.controller.switches = {sw1.dpid: sw1, sw2.dpid: sw2}
42 1
        self.api_client = get_test_client(controller, self.napp)
43 1
        self.base_endpoint = "amlight/sdntrace_cp/v1"
44 1
        self.trace_endpoint = f"{self.base_endpoint}/trace"
45 1
        self.traces_endpoint = f"{self.base_endpoint}/traces"
46
47 1
    @patch("napps.amlight.sdntrace_cp.main.Main.match_and_apply")
48 1
    def test_trace_step(self, mock_flow_match):
49
        """Test trace_step success result."""
50 1
        mock_flow_match.return_value = ["1"], ["entries"], 1
51 1
        switch = get_switch_mock("00:00:00:00:00:00:00:01", 0x04)
52
53 1
        mock_interface = Interface("interface A", 1, MagicMock())
54 1
        mock_interface.address = "00:00:00:00:00:00:00:01"
55
56 1
        iface1 = get_interface_mock(
57
            "", 1, get_switch_mock("00:00:00:00:00:00:00:01")
58
        )
59 1
        iface2 = get_interface_mock(
60
            "", 2, get_switch_mock("00:00:00:00:00:00:00:02")
61
        )
62 1
        mock_interface.link = get_link_mock(iface1, iface2)
63 1
        mock_interface.link.endpoint_a.port_number = 1
64 1
        mock_interface.link.endpoint_a.port_number = 2
65
66
        # Patch for utils.find_endpoint
67 1
        switch.get_interface_by_port_no.return_value = mock_interface
68
69 1
        entries = MagicMock()
70
71 1
        stored_flows = {
72
            "flow": {
73
                "table_id": 0,
74
                "cookie": 84114964,
75
                "hard_timeout": 0,
76
                "idle_timeout": 0,
77
                "priority": 10,
78
            },
79
            "flow_id": 1,
80
            "state": "installed",
81
            "switch": "00:00:00:00:00:00:00:01",
82
        }
83
84 1
        stored_flows_arg = {
85
            "00:00:00:00:00:00:00:01": [stored_flows]
86
        }
87
88 1
        result = self.napp.trace_step(switch, entries, stored_flows_arg)
89
90 1
        mock_flow_match.assert_called_once()
91 1
        assert result == {
92
                    "dpid": "00:00:00:00:00:00:00:01",
93
                    "in_port": 2,
94
                    "out_port": 1,
95
                    "entries": ["entries"],
96
                }
97
98 1
    @patch("napps.amlight.sdntrace_cp.main.Main.match_and_apply")
99 1
    def test_trace_step__no_endpoint(self, mock_flow_match):
100
        """Test trace_step without endpoints available for switch/port."""
101 1
        mock_flow_match.return_value = ["1"], ["entries"], 1
102 1
        switch = get_switch_mock("00:00:00:00:00:00:00:01", 0x04)
103
104 1
        mock_interface = Interface("interface A", 1, MagicMock())
105 1
        mock_interface.address = "00:00:00:00:00:00:00:01"
106 1
        mock_interface.link = None
107
108
        # Patch for utils.find_endpoint
109 1
        switch.get_interface_by_port_no.return_value = mock_interface
110
111 1
        entries = MagicMock()
112
113 1
        stored_flows = {
114
            "flow": {
115
                "table_id": 0,
116
                "cookie": 84114964,
117
                "hard_timeout": 0,
118
                "idle_timeout": 0,
119
                "priority": 10,
120
            },
121
            "flow_id": 1,
122
            "state": "installed",
123
            "switch": "00:00:00:00:00:00:00:01",
124
        }
125
126 1
        stored_flows_arg = {
127
            "00:00:00:00:00:00:00:01": [stored_flows]
128
        }
129
130 1
        result = self.napp.trace_step(switch, entries, stored_flows_arg)
131
132 1
        mock_flow_match.assert_called_once()
133 1
        assert result == {"entries": ["entries"], "out_port": 1}
134
135 1
    def test_trace_step__no_flow(self):
136
        """Test trace_step without flows for the switch."""
137 1
        switch = get_switch_mock("00:00:00:00:00:00:00:01")
138 1
        entries = MagicMock()
139
140 1
        stored_flows = {
141
            "flow": {
142
                "table_id": 0,
143
                "cookie": 84114964,
144
                "hard_timeout": 0,
145
                "idle_timeout": 0,
146
                "priority": 10,
147
            },
148
            "flow_id": 1,
149
            "state": "installed",
150
            "switch": "00:00:00:00:00:00:00:01",
151
        }
152
153 1
        stored_flows_arg = {
154
            "00:00:00:00:00:00:00:01": [stored_flows]
155
        }
156
157 1
        result = self.napp.trace_step(switch, entries, stored_flows_arg)
158 1
        assert result is None
159
160 1
    @patch("napps.amlight.sdntrace_cp.main.Main.trace_step")
161 1
    def test_tracepath(self, mock_trace_step):
162
        """Test tracepath with success result."""
163 1
        eth = {"dl_vlan": 100}
164 1
        dpid = {"dpid": "00:00:00:00:00:00:00:01", "in_port": 1}
165 1
        switch = {"switch": dpid, "eth": eth}
166 1
        entries = {"trace": switch}
167 1
        mock_trace_step.return_value = {
168
            "dpid": "00:00:00:00:00:00:00:02",
169
            "in_port": 2,
170
            "out_port": 3,
171
            "entries": entries,
172
        }
173
174 1
        stored_flows_arg = {
175
            "00:00:00:00:00:00:00:01": [],
176
            "00:00:00:00:00:00:00:02": [],
177
        }
178
179 1
        result = self.napp.tracepath(
180
                                        entries["trace"]["switch"],
181
                                        stored_flows_arg
182
                                    )
183
184 1
        assert result[0]["in"]["dpid"] == "00:00:00:00:00:00:00:01"
185 1
        assert result[0]["in"]["port"] == 1
186 1
        assert result[0]["in"]["type"] == "starting"
187 1
        assert result[0]["out"]["port"] == 3
188
189 1
        assert result[1]["in"]["dpid"] == "00:00:00:00:00:00:00:02"
190 1
        assert result[1]["in"]["port"] == 2
191 1
        assert result[1]["in"]["type"] == "intermediary"
192 1
        assert result[1]["out"]["port"] == 3
193
194 1
    @patch("napps.amlight.sdntrace_cp.main.Main.trace_step")
195 1
    def test_tracepath_loop(self, mock_trace_step):
196
        """Test tracepath with success result."""
197 1
        eth = {"dl_vlan": 100}
198 1
        dpid = {"dpid": "00:00:00:00:00:00:00:01", "in_port": 1}
199 1
        switch = {"switch": dpid, "eth": eth}
200 1
        entries = {"trace": switch}
201 1
        mock_trace_step.return_value = {
202
            "dpid": "00:00:00:00:00:00:00:01",
203
            "in_port": 1,
204
            "out_port": 1,
205
            "entries": entries,
206
        }
207
208 1
        result = self.napp.tracepath(
209
                                        entries["trace"]["switch"],
210
                                        {}
211
                                    )
212 1
        assert len(result) == 2
213
        # input interface = output interface
214 1
        assert result[0]["in"]["type"] == "starting"
215 1
        assert result[1]["in"]["type"] == "loop"
216
217 1
    def test_has_loop(self):
218
        """Test has_loop to detect a tracepath with loop."""
219 1
        trace_result = [
220
            {
221
                "in": {
222
                    "dpid": "00:00:00:00:00:00:00:01",
223
                    "port": 2,
224
                },
225
                "out": {
226
                    "port": 1,
227
                },
228
            },
229
            {
230
                "in": {
231
                    "dpid": "00:00:00:00:00:00:00:03",
232
                    "port": 2,
233
                },
234
                "out": {
235
                    "port": 1,
236
                },
237
            },
238
            {
239
                "in": {
240
                    "dpid": "00:00:00:00:00:00:00:03",
241
                    "port": 3,
242
                },
243
                "out": {
244
                    "port": 1,
245
                },
246
            },
247
            {
248
                "in": {
249
                    "dpid": "00:00:00:00:00:00:00:03",
250
                    "port": 3,
251
                },
252
                "out": {
253
                    "port": 1,
254
                },
255
            },
256
        ]
257 1
        trace_step = {
258
            "dpid": "00:00:00:00:00:00:00:03",
259
            "port": 3,
260
        }
261
262 1
        result = self.napp.has_loop(trace_step, trace_result)
263 1
        assert result
264
265 1
    def test_has_loop__fail(self):
266
        """Test has_loop to detect a tracepath with loop."""
267 1
        trace_result = [
268
            {
269
                "in": {
270
                    "dpid": "00:00:00:00:00:00:00:01",
271
                    "port": 2,
272
                },
273
                "out": {
274
                    "port": 1,
275
                },
276
            },
277
            {
278
                "in": {
279
                    "dpid": "00:00:00:00:00:00:00:02",
280
                    "port": 2,
281
                },
282
                "out": {
283
                    "port": 1,
284
                },
285
            },
286
        ]
287 1
        trace_step = {
288
            "dpid": "00:00:00:00:00:00:00:03",
289
            "port": 2,
290
        }
291
292 1
        result = self.napp.has_loop(trace_step, trace_result)
293 1
        assert not result
294
295 1 View Code Duplication
    @patch("napps.amlight.sdntrace_cp.main.get_stored_flows")
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
296 1
    async def test_trace(self, mock_stored_flows, event_loop):
297
        """Test trace rest call."""
298 1
        self.napp.controller.loop = event_loop
299 1
        payload = {
300
            "trace": {
301
                "switch": {
302
                    "dpid": "00:00:00:00:00:00:00:01",
303
                    "in_port": 1
304
                    },
305
                "eth": {"dl_vlan": 100},
306
            }
307
        }
308 1
        stored_flows = {
309
                "flow": {
310
                    "table_id": 0,
311
                    "cookie": 84114964,
312
                    "hard_timeout": 0,
313
                    "idle_timeout": 0,
314
                    "priority": 10,
315
                    "match": {"dl_vlan": 100, "in_port": 1},
316
                    "actions": [
317
                        {"action_type": "push_vlan"},
318
                        {"action_type": "set_vlan", "vlan_id": 200},
319
                        {"action_type": "output", "port": 2}
320
                    ],
321
                },
322
                "flow_id": 1,
323
                "state": "installed",
324
                "switch": "00:00:00:00:00:00:00:01",
325
        }
326 1
        mock_stored_flows.return_value = {
327
            "00:00:00:00:00:00:00:01": [stored_flows]
328
        }
329
330 1
        resp = await self.api_client.put(self.trace_endpoint, json=payload)
331 1
        assert resp.status_code == 200
332 1
        current_data = resp.json()
333 1
        result = current_data["result"]
334
335 1
        assert len(result) == 1
336 1
        assert result[0]["dpid"] == "00:00:00:00:00:00:00:01"
337 1
        assert result[0]["port"] == 1
338 1
        assert result[0]["type"] == "last"
339 1
        assert result[0]["vlan"] == 100
340 1
        assert result[0]["out"] == {"port": 2, "vlan": 200}
341
342 1 View Code Duplication
    @patch("napps.amlight.sdntrace_cp.main.get_stored_flows")
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
343 1
    async def test_trace_instructions(self, mock_stored_flows, event_loop):
344
        """Test trace rest call with instructions."""
345 1
        self.napp.controller.loop = event_loop
346 1
        payload = {
347
            "trace": {
348
                "switch": {
349
                    "dpid": "00:00:00:00:00:00:00:01",
350
                    "in_port": 1
351
                    },
352
                "eth": {"dl_vlan": 100},
353
            }
354
        }
355 1
        stored_flows = {
356
                "flow": {
357
                    "table_id": 0,
358
                    "cookie": 84114964,
359
                    "hard_timeout": 0,
360
                    "idle_timeout": 0,
361
                    "priority": 10,
362
                    "match": {"dl_vlan": 100, "in_port": 1},
363
                    "instructions": [
364
                        {
365
                            "instruction_type": "apply_actions",
366
                            "actions": [
367
                                {"action_type": "push_vlan"},
368
                                {"action_type": "set_vlan", "vlan_id": 200},
369
                                {"action_type": "output", "port": 2}
370
                            ]
371
                        }
372
                    ]
373
                },
374
                "flow_id": 1,
375
                "state": "installed",
376
                "switch": "00:00:00:00:00:00:00:01",
377
        }
378 1
        mock_stored_flows.return_value = {
379
            "00:00:00:00:00:00:00:01": [stored_flows]
380
        }
381
382 1
        resp = await self.api_client.put(self.trace_endpoint, json=payload)
383 1
        assert resp.status_code == 200
384 1
        current_data = resp.json()
385 1
        result = current_data["result"]
386
387 1
        assert len(result) == 1
388 1
        assert result[0]["dpid"] == "00:00:00:00:00:00:00:01"
389 1
        assert result[0]["port"] == 1
390 1
        assert result[0]["type"] == "last"
391 1
        assert result[0]["vlan"] == 100
392 1
        assert result[0]["out"] == {"port": 2, "vlan": 200}
393
394 1
    @patch("napps.amlight.sdntrace_cp.main.get_stored_flows")
395 1
    async def test_trace_fail(self, mock_stored_flows, event_loop):
396
        """Test trace with a failed dependency."""
397 1
        self.napp.controller.loop = event_loop
398 1
        mock_stored_flows.side_effect = HTTPException(424, "failed")
399 1
        payload = {
400
            "trace": {
401
                "switch": {
402
                    "dpid": "00:00:00:00:00:00:00:01",
403
                    "in_port": 1
404
                    },
405
                "eth": {"dl_vlan": 100},
406
            }
407
        }
408 1
        response = await self.api_client.put(self.trace_endpoint, json=payload)
409 1
        assert response.status_code == 424
410
411 1 View Code Duplication
    @patch("napps.amlight.sdntrace_cp.main.get_stored_flows")
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
412 1
    async def test_get_traces(self, mock_stored_flows, event_loop):
413
        """Test traces rest call."""
414 1
        self.napp.controller.loop = event_loop
415 1
        payload = [{
416
            "trace": {
417
                "switch": {
418
                    "dpid": "00:00:00:00:00:00:00:01",
419
                    "in_port": 1
420
                    },
421
                "eth": {"dl_vlan": 100},
422
            }
423
        }]
424
425 1
        stored_flow = {
426
            "id": 1,
427
            "flow": {
428
                "table_id": 0,
429
                "cookie": 84114964,
430
                "hard_timeout": 0,
431
                "idle_timeout": 0,
432
                "priority": 10,
433
                "match": {"dl_vlan": 100, "in_port": 1},
434
                "actions": [
435
                    {"action_type": "pop_vlan"},
436
                    {"action_type": "output", "port": 2},
437
                ],
438
            }
439
        }
440
441 1
        mock_stored_flows.return_value = {
442
            "00:00:00:00:00:00:00:01": [stored_flow]
443
        }
444
445 1
        resp = await self.api_client.put(self.traces_endpoint, json=payload)
446 1
        assert resp.status_code == 200
447 1
        current_data = resp.json()
448 1
        result1 = current_data["result"]
449
450 1
        assert len(result1) == 1
451 1
        assert len(result1[0]) == 1
452 1
        assert result1[0][0]["dpid"] == "00:00:00:00:00:00:00:01"
453 1
        assert result1[0][0]["port"] == 1
454 1
        assert result1[0][0]["type"] == "last"
455 1
        assert result1[0][0]["vlan"] == 100
456 1
        assert result1[0][0]["out"] == {"port": 2}
457
458 1
    @patch("napps.amlight.sdntrace_cp.main.get_stored_flows")
459 1
    async def test_traces(self, mock_stored_flows, event_loop):
460
        """Test traces rest call"""
461 1
        self.napp.controller.loop = event_loop
462 1
        payload = [
463
                    {
464
                        "trace": {
465
                            "switch": {
466
                                "dpid": "00:00:00:00:00:00:00:01",
467
                                "in_port": 1
468
                            },
469
                            "eth": {
470
                                "dl_vlan": 100
471
                            }
472
                        }
473
                    },
474
                    {
475
                        "trace": {
476
                            "switch": {
477
                                "dpid": "00:00:00:00:00:00:00:0a",
478
                                "in_port": 1
479
                            },
480
                            "eth": {
481
                                "dl_vlan": 100
482
                            }
483
                        }
484
                    },
485
                    {
486
                        "trace": {
487
                            "switch": {
488
                                "dpid": "00:00:00:00:00:00:00:02",
489
                                "in_port": 2
490
                            },
491
                            "eth": {
492
                                "dl_vlan": 100
493
                            }
494
                        }
495
                    }
496
                ]
497
498 1
        stored_flow = {
499
            "id": 1,
500
            "flow": {
501
                "table_id": 0,
502
                "cookie": 84114964,
503
                "hard_timeout": 0,
504
                "idle_timeout": 0,
505
                "priority": 10,
506
                "match": {"dl_vlan": 100, "in_port": 1},
507
                "actions": [{"action_type": "output", "port": 2}],
508
            }
509
        }
510
511 1
        mock_stored_flows.return_value = {
512
            "00:00:00:00:00:00:00:01": [stored_flow],
513
            "00:00:00:00:00:00:00:02": [stored_flow],
514
        }
515
516 1
        resp = await self.api_client.put(self.traces_endpoint, json=payload)
517 1
        assert resp.status_code == 200
518 1
        current_data = resp.json()
519 1
        result = current_data["result"]
520 1
        assert len(result) == 3
521
522 1
        assert result[0][0]["dpid"] == "00:00:00:00:00:00:00:01"
523 1
        assert result[0][0]["port"] == 1
524 1
        assert result[0][0]["type"] == "last"
525 1
        assert result[0][0]["vlan"] == 100
526 1
        assert result[0][0]["out"] == {"port": 2, "vlan": 100}
527
528 1
        assert result[1][0]["dpid"] == "00:00:00:00:00:00:00:0a"
529 1
        assert result[1][0]["port"] == 1
530 1
        assert result[1][0]["type"] == "last"
531 1
        assert result[1][0]["vlan"] == 100
532 1
        assert result[1][0]["out"] is None
533
534 1
        assert len(result[2]) == 0
535
536 1
    @patch("napps.amlight.sdntrace_cp.main.get_stored_flows")
537 1
    async def test_traces_fail(self, mock_stored_flows, event_loop):
538
        """Test traces with a failed dependency."""
539 1
        self.napp.controller.loop = event_loop
540 1
        mock_stored_flows.side_effect = HTTPException(424, "failed")
541 1
        payload = [{
542
            "trace": {
543
                "switch": {
544
                    "dpid": "00:00:00:00:00:00:00:01",
545
                    "in_port": 1
546
                    },
547
                "eth": {"dl_vlan": 100},
548
            }
549
        }]
550 1
        resp = await self.api_client.put(self.traces_endpoint, json=payload)
551 1
        assert resp.status_code == 424
552
553 1 View Code Duplication
    @patch("napps.amlight.sdntrace_cp.main.get_stored_flows")
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
554 1
    async def test_traces_with_loop(self, mock_stored_flows, event_loop):
555
        """Test traces rest call"""
556 1
        self.napp.controller.loop = event_loop
557 1
        payload = [
558
                    {
559
                        "trace": {
560
                            "switch": {
561
                                "dpid": "00:00:00:00:00:00:00:01",
562
                                "in_port": 1
563
                            },
564
                            "eth": {
565
                                "dl_vlan": 100
566
                            }
567
                        }
568
                    }
569
                ]
570
571 1
        stored_flow = {
572
            "id": 1,
573
            "flow": {
574
                "table_id": 0,
575
                "cookie": 84114964,
576
                "hard_timeout": 0,
577
                "idle_timeout": 0,
578
                "priority": 10,
579
                "match": {"dl_vlan": 100, "in_port": 1},
580
                "actions": [{"action_type": "output", "port": 1}],
581
            }
582
        }
583
584 1
        mock_stored_flows.return_value = {
585
            "00:00:00:00:00:00:00:01": [stored_flow],
586
        }
587
588 1
        resp = await self.api_client.put(self.traces_endpoint, json=payload)
589 1
        assert resp.status_code == 200
590 1
        current_data = resp.json()
591 1
        result = current_data["result"]
592 1
        assert len(result) == 1
593 1
        assert result[0][0]["dpid"] == "00:00:00:00:00:00:00:01"
594 1
        assert result[0][0]["port"] == 1
595 1
        assert result[0][0]["type"] == "loop"
596 1
        assert result[0][0]["vlan"] == 100
597 1
        assert result[0][0]["out"] == {"port": 1, "vlan": 100}
598
599 1
    @patch("napps.amlight.sdntrace_cp.main.get_stored_flows")
600 1
    async def test_traces_no_action(self, mock_stored_flows, event_loop):
601
        """Test traces rest call for two traces with different switches."""
602 1
        self.napp.controller.loop = event_loop
603 1
        payload = [
604
            {
605
                "trace": {
606
                    "switch": {
607
                        "dpid": "00:00:00:00:00:00:00:01",
608
                        "in_port": 1
609
                        },
610
                    "eth": {"dl_vlan": 100},
611
                }
612
            },
613
            {
614
                "trace": {
615
                    "switch": {
616
                        "dpid": "00:00:00:00:00:00:00:02",
617
                        "in_port": 1},
618
                    "eth": {"dl_vlan": 100},
619
                }
620
            }
621
        ]
622
623 1
        stored_flow1 = {
624
            "id": 1,
625
            "flow": {
626
                "table_id": 0,
627
                "cookie": 84114964,
628
                "hard_timeout": 0,
629
                "idle_timeout": 0,
630
                "priority": 10,
631
                "match": {"dl_vlan": 100, "in_port": 1}
632
            }
633
        }
634 1
        stored_flow2 = {
635
            "id": 1,
636
            "flow": {
637
                "table_id": 0,
638
                "cookie": 84114964,
639
                "hard_timeout": 0,
640
                "idle_timeout": 0,
641
                "priority": 10,
642
                "match": {"dl_vlan": 100, "in_port": 1},
643
                "actions": []
644
            }
645
        }
646
647 1
        mock_stored_flows.return_value = {
648
            "00:00:00:00:00:00:00:01": [stored_flow1],
649
            "00:00:00:00:00:00:00:02": [stored_flow2]
650
        }
651
652 1
        resp = await self.api_client.put(self.traces_endpoint, json=payload)
653 1
        assert resp.status_code == 200
654 1
        current_data = resp.json()
655 1
        result = current_data["result"]
656 1
        assert len(result) == 2
657 1
        assert len(result[0]) == 0
658 1
        assert len(result[1]) == 0
659
660 1
    @patch("napps.amlight.sdntrace_cp.main.get_stored_flows")
661 1
    async def test_get_traces_untagged(self, mock_stored_flows, event_loop):
662
        """Test traces rest call."""
663 1
        self.napp.controller.loop = event_loop
664 1
        payload = [{
665
            "trace": {
666
                "switch": {
667
                    "dpid": "00:00:00:00:00:00:00:01",
668
                    "in_port": 1
669
                    },
670
                "eth": {"dl_vlan": 10},
671
            }
672
        }, {
673
            "trace": {
674
                "switch": {
675
                    "dpid": "00:00:00:00:00:00:00:01",
676
                    "in_port": 1
677
                    }
678
            }
679
        }
680
        ]
681
682 1
        stored_flow1 = {
683
            "flow": {
684
                "match": {"dl_vlan": 0, "in_port": 1},
685
                "actions": [
686
                    {"action_type": "pop_vlan"},
687
                    {"action_type": "output", "port": 2},
688
                ],
689
            }
690
        }
691 1
        stored_flow2 = {
692
            "flow": {
693
                "match": {"in_port": 1},
694
                "actions": [
695
                    {"action_type": "pop_vlan"},
696
                    {"action_type": "output", "port": 3},
697
                ],
698
            }
699
        }
700 1
        stored_flow3 = {
701
            "flow": {
702
                "match": {"dl_vlan": 10, "in_port": 1},
703
                "actions": [
704
                    {"action_type": "pop_vlan"},
705
                    {"action_type": "output", "port": 1},
706
                ],
707
            }
708
        }
709 1
        mock_stored_flows.return_value = {
710
            "00:00:00:00:00:00:00:01": [
711
                stored_flow1,
712
                stored_flow2,
713
                stored_flow3
714
            ]
715
        }
716
717 1
        resp = await self.api_client.put(self.traces_endpoint, json=payload)
718 1
        assert resp.status_code == 200
719 1
        current_data = resp.json()
720
721 1
        result = current_data["result"]
722 1
        assert result[0][0]["type"] == "last"
723 1
        assert result[0][0]["out"] == {"port": 3}
724 1
        assert result[1][0]["type"] == "last"
725 1
        assert result[1][0]["out"] == {"port": 2}
726
727 1
        mock_stored_flows.return_value = {
728
            "00:00:00:00:00:00:00:01": [
729
                stored_flow3,
730
                stored_flow2,
731
                stored_flow1
732
            ]
733
        }
734
735 1
        resp = await self.api_client.put(self.traces_endpoint, json=payload)
736 1
        assert resp.status_code == 200
737 1
        current_data = resp.json()
738 1
        result = current_data["result"]
739 1
        assert result[0][0]["type"] == "loop"
740 1
        assert result[0][0]["out"] == {"port": 1}
741 1
        assert result[1][0]["type"] == "last"
742 1
        assert result[1][0]["out"] == {"port": 3}
743
744 1
    @patch("napps.amlight.sdntrace_cp.main.get_stored_flows")
745 1
    async def test_get_traces_any(self, mock_stored_flows, event_loop):
746
        """Test traces rest call."""
747 1
        self.napp.controller.loop = event_loop
748 1
        payload = [{
749
            "trace": {
750
                "switch": {
751
                    "dpid": "00:00:00:00:00:00:00:01",
752
                    "in_port": 1
753
                    },
754
                "eth": {"dl_vlan": 10}
755
            }
756
        }, {
757
            "trace": {
758
                "switch": {
759
                    "dpid": "00:00:00:00:00:00:00:01",
760
                    "in_port": 1
761
                    }
762
            }
763
        }
764
        ]
765
766 1
        stored_flow1 = {
767
            "flow": {
768
                "match": {"dl_vlan": "4096/4096", "in_port": 1},
769
                "actions": [
770
                    {"action_type": "pop_vlan"},
771
                    {"action_type": "output", "port": 2},
772
                ],
773
            }
774
        }
775 1
        stored_flow2 = {
776
            "flow": {
777
                "match": {"dl_vlan": 10, "in_port": 1},
778
                "actions": [
779
                    {"action_type": "pop_vlan"},
780
                    {"action_type": "output", "port": 1},
781
                ],
782
            }
783
        }
784 1
        stored_flow3 = {
785
            "flow": {
786
                "match": {"dl_vlan": "10/10", "in_port": 1},
787
                "actions": [
788
                    {"action_type": "pop_vlan"},
789
                    {"action_type": "output", "port": 3},
790
                ],
791
            }
792
        }
793 1
        stored_flow4 = {
794
            "flow": {
795
                "match": {"dl_vlan": "20/10", "in_port": 1},
796
                "actions": [
797
                    {"action_type": "pop_vlan"},
798
                    {"action_type": "output", "port": 1},
799
                ],
800
            }
801
        }
802 1
        mock_stored_flows.return_value = {
803
            "00:00:00:00:00:00:00:01": [
804
                stored_flow1,
805
                stored_flow2,
806
                stored_flow3,
807
                stored_flow4
808
            ]
809
        }
810
811 1
        resp = await self.api_client.put(self.traces_endpoint, json=payload)
812 1
        assert resp.status_code == 200
813 1
        current_data = resp.json()
814 1
        result = current_data["result"]
815 1
        assert result[0][0]["type"] == "last"
816 1
        assert result[0][0]["out"] == {"port": 2}
817 1
        assert len(result[1]) == 0
818
819 1
        mock_stored_flows.return_value = {
820
            "00:00:00:00:00:00:00:01": [
821
                stored_flow4,
822
                stored_flow3,
823
                stored_flow2,
824
                stored_flow1
825
            ]
826
        }
827
828 1
        resp = await self.api_client.put(self.traces_endpoint, json=payload)
829 1
        assert resp.status_code == 200
830 1
        current_data = resp.json()
831 1
        result = current_data["result"]
832 1
        assert result[0][0]["type"] == "last"
833 1
        assert result[0][0]["out"] == {"port": 3}
834 1
        assert len(result[1]) == 0
835
836 1
    @pytest.mark.parametrize(
837
        "flow,args,match",
838
        [
839
            (
840
                {'flow': {'match': {'dl_vlan': 10}}},
841
                {'dl_vlan': [10]},
842
                {'flow': {'match': {'dl_vlan': 10}}},
843
            ),
844
            (
845
                {'flow': {'match': {'dl_vlan': 0}}},
846
                {},
847
                {'flow': {'match': {'dl_vlan': 0}}},
848
            ),
849
            (
850
                {'flow': {'match': {'dl_vlan': '10/10'}}},
851
                {'dl_vlan': [10]},
852
                {'flow': {'match': {'dl_vlan': '10/10'}}},
853
            ),
854
            (
855
                {'flow': {'match': {'dl_vlan': '10/10'}}},
856
                {'dl_vlan': [2]},
857
                False,
858
            ),
859
            (
860
                {'flow': {'match': {
861
                                    'nw_src': '192.168.20.21/10',
862
                                    'nw_dst': '192.168.20.21/32',
863
                                    'ipv6_src': '2002:db8::8a3f:362:7897/10',
864
                                    'ipv6_dst': '2002:db8::8a3f:362:7897/128',
865
                                    }
866
                          }
867
                 },
868
                {
869
                        'nw_src': '192.168.20.21',
870
                        'nw_dst': '192.168.20.21',
871
                        'ipv6_src': '2002:db8::8a3f:362:7897',
872
                        'ipv6_dst': '2002:db8::8a3f:362:7897',
873
                },
874
                {'flow': {'match': {
875
                                    'nw_src': '192.168.20.21/10',
876
                                    'nw_dst': '192.168.20.21/32',
877
                                    'ipv6_src': '2002:db8::8a3f:362:7897/10',
878
                                    'ipv6_dst': '2002:db8::8a3f:362:7897/128',
879
                                    }
880
                          }
881
                 },
882
            ),
883
            (
884
                {'flow': {'match': {'nw_src': '192.168.20.21'}}},
885
                {'nw_src': '192.168.20.30'},
886
                False,
887
            ),
888
            (
889
                {'flow': {'match': {'ipv6_src': '2002:db8::8a3f:362:7'}}},
890
                {'ipv6_src': '2002:db8::8a3f:362:7897'},
891
                False,
892
            ),
893
            (
894
                {'flow': {'match': {'in_port': 1, 'dl_vlan': '4096/4096'}}},
895
                {'in_port': 1, 'dl_vlan': [1]},
896
                {'flow': {'match': {'in_port': 1, 'dl_vlan': '4096/4096'}}},
897
            ),
898
            (
899
                {'flow': {'match': {'in_port': 1, 'dl_vlan': '4096/4096'}}},
900
                {'dl_vlan': [1]},
901
                False,
902
            ),
903
        ],
904
    )
905 1
    def test_do_match(self, flow, args, match):
906
        """Test do_match."""
907 1
        assert self.napp.do_match(flow, args) == match
908
909 1
    def test_match_flows(self):
910
        """Test match_flows."""
911 1
        flow = {"flow": {"match": {"dl_vlan": "10/10", "in_port": 1}}}
912 1
        switch = get_switch_mock("00:00:00:00:00:00:00:01")
913 1
        stored_flows = {"00:00:00:00:00:00:00:01": [flow]}
914 1
        args = {"dl_vlan": [10], "in_port": 1}
915 1
        resp = self.napp.match_flows(switch, args, stored_flows)
916 1
        assert resp == [flow]
917
918 1
        stored_flows = {}
919 1
        resp = self.napp.match_flows(switch, args, stored_flows)
920 1
        assert not resp
921
922 1
    @pytest.mark.parametrize(
923
        "flow,args,resp",
924
        [
925
            (
926
                {"flow": {
927
                          "match": {"dl_vlan": "10/10", "in_port": 1},
928
                          "actions": [{'action_type': 'output', 'port': 1}]
929
                          }
930
                 },
931
                {"dl_vlan": [10], "in_port": 1},
932
                ({"flow": {
933
                            "match": {"dl_vlan": "10/10", "in_port": 1},
934
                            "actions": [{'action_type': 'output', 'port': 1}]
935
                            }
936
                  }, {"dl_vlan": [10], "in_port": 1}, 1),
937
            ),
938
            (
939
                {"flow": {
940
                          "match": {"dl_vlan": "10/10", "in_port": 1},
941
                          "actions": [{'action_type': 'push_vlan'}]
942
                          }
943
                 },
944
                {"dl_vlan": [10], "in_port": 1},
945
                ({"flow": {
946
                            "match": {"dl_vlan": "10/10", "in_port": 1},
947
                            "actions": [{'action_type': 'push_vlan'}]
948
                            }
949
                  }, {"dl_vlan": [10, 0], "in_port": 1}, None),
950
            ),
951
            (
952
                {"flow": {
953
                          "match": {"dl_vlan": "10/10", "in_port": 1},
954
                          "actions": [{'action_type': 'pop_vlan'}]
955
                          }
956
                 },
957
                {"dl_vlan": [10], "in_port": 1},
958
                ({"flow": {
959
                            "match": {"dl_vlan": "10/10", "in_port": 1},
960
                            "actions": [{'action_type': 'pop_vlan'}]
961
                            }
962
                  }, {"in_port": 1}, None),
963
            ),
964
            (
965
                {"flow": {
966
                          "match": {"dl_vlan": "10/10", "in_port": 1},
967
                          "actions": [{'action_type': 'set_vlan',
968
                                       'vlan_id': 2}]
969
                          }
970
                 },
971
                {"dl_vlan": [10], "in_port": 1},
972
                ({"flow": {
973
                            "match": {"dl_vlan": "10/10", "in_port": 1},
974
                            "actions": [{'action_type': 'set_vlan',
975
                                         'vlan_id': 2}]
976
                            }
977
                  }, {"dl_vlan": [2], "in_port": 1}, None),
978
            ),
979
        ],
980
    )
981 1
    def test_match_and_apply(self, flow, args, resp):
982
        """Test match_and_apply."""
983 1
        switch = get_switch_mock("00:00:00:00:00:00:00:01", 0x04)
984 1
        stored_flows = {"00:00:00:00:00:00:00:01": [flow]}
985 1
        assert self.napp.match_and_apply(switch, args, stored_flows) == resp
986
987 1
        stored_flows = {}
988 1
        resp = self.napp.match_and_apply(switch, args, stored_flows)
989 1
        assert not resp[0]
990
        assert not resp[2]
991