Passed
Push — master ( a80f24...c58985 )
by
unknown
02:10 queued 12s
created

TestMain.test_trace_step__no_endpoint()   A

Complexity

Conditions 1

Size

Total Lines 36
Code Lines 24

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 14
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 24
nop 2
dl 0
loc 36
ccs 14
cts 14
cp 1
crap 1
rs 9.304
c 0
b 0
f 0
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
    @patch("napps.amlight.sdntrace_cp.main.get_stored_flows")
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
    @patch("napps.amlight.sdntrace_cp.main.get_stored_flows")
343 1
    async def test_trace_fail(self, mock_stored_flows, event_loop):
344
        """Test trace with a failed dependency."""
345 1
        self.napp.controller.loop = event_loop
346 1
        mock_stored_flows.side_effect = HTTPException(424, "failed")
347 1
        payload = {
348
            "trace": {
349
                "switch": {
350
                    "dpid": "00:00:00:00:00:00:00:01",
351
                    "in_port": 1
352
                    },
353
                "eth": {"dl_vlan": 100},
354
            }
355
        }
356 1
        response = await self.api_client.put(self.trace_endpoint, json=payload)
357 1
        assert response.status_code == 424
358
359 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...
360 1
    async def test_get_traces(self, mock_stored_flows, event_loop):
361
        """Test traces rest call."""
362 1
        self.napp.controller.loop = event_loop
363 1
        payload = [{
364
            "trace": {
365
                "switch": {
366
                    "dpid": "00:00:00:00:00:00:00:01",
367
                    "in_port": 1
368
                    },
369
                "eth": {"dl_vlan": 100},
370
            }
371
        }]
372
373 1
        stored_flow = {
374
            "id": 1,
375
            "flow": {
376
                "table_id": 0,
377
                "cookie": 84114964,
378
                "hard_timeout": 0,
379
                "idle_timeout": 0,
380
                "priority": 10,
381
                "match": {"dl_vlan": 100, "in_port": 1},
382
                "actions": [
383
                    {"action_type": "pop_vlan"},
384
                    {"action_type": "output", "port": 2},
385
                ],
386
            }
387
        }
388
389 1
        mock_stored_flows.return_value = {
390
            "00:00:00:00:00:00:00:01": [stored_flow]
391
        }
392
393 1
        resp = await self.api_client.put(self.traces_endpoint, json=payload)
394 1
        assert resp.status_code == 200
395 1
        current_data = resp.json()
396 1
        result1 = current_data["result"]
397
398 1
        assert len(result1) == 1
399 1
        assert len(result1[0]) == 1
400 1
        assert result1[0][0]["dpid"] == "00:00:00:00:00:00:00:01"
401 1
        assert result1[0][0]["port"] == 1
402 1
        assert result1[0][0]["type"] == "last"
403 1
        assert result1[0][0]["vlan"] == 100
404 1
        assert result1[0][0]["out"] == {"port": 2}
405
406 1
    @patch("napps.amlight.sdntrace_cp.main.get_stored_flows")
407 1
    async def test_traces(self, mock_stored_flows, event_loop):
408
        """Test traces rest call"""
409 1
        self.napp.controller.loop = event_loop
410 1
        payload = [
411
                    {
412
                        "trace": {
413
                            "switch": {
414
                                "dpid": "00:00:00:00:00:00:00:01",
415
                                "in_port": 1
416
                            },
417
                            "eth": {
418
                                "dl_vlan": 100
419
                            }
420
                        }
421
                    },
422
                    {
423
                        "trace": {
424
                            "switch": {
425
                                "dpid": "00:00:00:00:00:00:00:0a",
426
                                "in_port": 1
427
                            },
428
                            "eth": {
429
                                "dl_vlan": 100
430
                            }
431
                        }
432
                    },
433
                    {
434
                        "trace": {
435
                            "switch": {
436
                                "dpid": "00:00:00:00:00:00:00:02",
437
                                "in_port": 2
438
                            },
439
                            "eth": {
440
                                "dl_vlan": 100
441
                            }
442
                        }
443
                    }
444
                ]
445
446 1
        stored_flow = {
447
            "id": 1,
448
            "flow": {
449
                "table_id": 0,
450
                "cookie": 84114964,
451
                "hard_timeout": 0,
452
                "idle_timeout": 0,
453
                "priority": 10,
454
                "match": {"dl_vlan": 100, "in_port": 1},
455
                "actions": [{"action_type": "output", "port": 2}],
456
            }
457
        }
458
459 1
        mock_stored_flows.return_value = {
460
            "00:00:00:00:00:00:00:01": [stored_flow],
461
            "00:00:00:00:00:00:00:02": [stored_flow],
462
        }
463
464 1
        resp = await self.api_client.put(self.traces_endpoint, json=payload)
465 1
        assert resp.status_code == 200
466 1
        current_data = resp.json()
467 1
        result = current_data["result"]
468 1
        assert len(result) == 3
469
470 1
        assert result[0][0]["dpid"] == "00:00:00:00:00:00:00:01"
471 1
        assert result[0][0]["port"] == 1
472 1
        assert result[0][0]["type"] == "last"
473 1
        assert result[0][0]["vlan"] == 100
474 1
        assert result[0][0]["out"] == {"port": 2, "vlan": 100}
475
476 1
        assert result[1][0]["dpid"] == "00:00:00:00:00:00:00:0a"
477 1
        assert result[1][0]["port"] == 1
478 1
        assert result[1][0]["type"] == "last"
479 1
        assert result[1][0]["vlan"] == 100
480 1
        assert result[1][0]["out"] is None
481
482 1
        assert result[2][0]["dpid"] == "00:00:00:00:00:00:00:02"
483 1
        assert result[2][0]["port"] == 2
484 1
        assert result[2][0]["type"] == "incomplete"
485 1
        assert result[2][0]["vlan"] == 100
486 1
        assert result[2][0]["out"] is None
487
488 1
    @patch("napps.amlight.sdntrace_cp.main.get_stored_flows")
489 1
    async def test_traces_fail(self, mock_stored_flows, event_loop):
490
        """Test traces with a failed dependency."""
491 1
        self.napp.controller.loop = event_loop
492 1
        mock_stored_flows.side_effect = HTTPException(424, "failed")
493 1
        payload = [{
494
            "trace": {
495
                "switch": {
496
                    "dpid": "00:00:00:00:00:00:00:01",
497
                    "in_port": 1
498
                    },
499
                "eth": {"dl_vlan": 100},
500
            }
501
        }]
502 1
        resp = await self.api_client.put(self.traces_endpoint, json=payload)
503 1
        assert resp.status_code == 424
504
505 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...
506 1
    async def test_traces_with_loop(self, mock_stored_flows, event_loop):
507
        """Test traces rest call"""
508 1
        self.napp.controller.loop = event_loop
509 1
        payload = [
510
                    {
511
                        "trace": {
512
                            "switch": {
513
                                "dpid": "00:00:00:00:00:00:00:01",
514
                                "in_port": 1
515
                            },
516
                            "eth": {
517
                                "dl_vlan": 100
518
                            }
519
                        }
520
                    }
521
                ]
522
523 1
        stored_flow = {
524
            "id": 1,
525
            "flow": {
526
                "table_id": 0,
527
                "cookie": 84114964,
528
                "hard_timeout": 0,
529
                "idle_timeout": 0,
530
                "priority": 10,
531
                "match": {"dl_vlan": 100, "in_port": 1},
532
                "actions": [{"action_type": "output", "port": 1}],
533
            }
534
        }
535
536 1
        mock_stored_flows.return_value = {
537
            "00:00:00:00:00:00:00:01": [stored_flow],
538
        }
539
540 1
        resp = await self.api_client.put(self.traces_endpoint, json=payload)
541 1
        assert resp.status_code == 200
542 1
        current_data = resp.json()
543 1
        result = current_data["result"]
544 1
        assert len(result) == 1
545 1
        assert result[0][0]["dpid"] == "00:00:00:00:00:00:00:01"
546 1
        assert result[0][0]["port"] == 1
547 1
        assert result[0][0]["type"] == "loop"
548 1
        assert result[0][0]["vlan"] == 100
549 1
        assert result[0][0]["out"] == {"port": 1, "vlan": 100}
550
551 1
    @patch("napps.amlight.sdntrace_cp.main.get_stored_flows")
552 1
    async def test_traces_no_action(self, mock_stored_flows, event_loop):
553
        """Test traces rest call for two traces with different switches."""
554 1
        self.napp.controller.loop = event_loop
555 1
        payload = [
556
            {
557
                "trace": {
558
                    "switch": {
559
                        "dpid": "00:00:00:00:00:00:00:01",
560
                        "in_port": 1
561
                        },
562
                    "eth": {"dl_vlan": 100},
563
                }
564
            },
565
            {
566
                "trace": {
567
                    "switch": {
568
                        "dpid": "00:00:00:00:00:00:00:02",
569
                        "in_port": 1},
570
                    "eth": {"dl_vlan": 100},
571
                }
572
            }
573
        ]
574
575 1
        stored_flow1 = {
576
            "id": 1,
577
            "flow": {
578
                "table_id": 0,
579
                "cookie": 84114964,
580
                "hard_timeout": 0,
581
                "idle_timeout": 0,
582
                "priority": 10,
583
                "match": {"dl_vlan": 100, "in_port": 1}
584
            }
585
        }
586 1
        stored_flow2 = {
587
            "id": 1,
588
            "flow": {
589
                "table_id": 0,
590
                "cookie": 84114964,
591
                "hard_timeout": 0,
592
                "idle_timeout": 0,
593
                "priority": 10,
594
                "match": {"dl_vlan": 100, "in_port": 1},
595
                "actions": []
596
            }
597
        }
598
599 1
        mock_stored_flows.return_value = {
600
            "00:00:00:00:00:00:00:01": [stored_flow1],
601
            "00:00:00:00:00:00:00:02": [stored_flow2]
602
        }
603
604 1
        resp = await self.api_client.put(self.traces_endpoint, json=payload)
605 1
        assert resp.status_code == 200
606 1
        current_data = resp.json()
607 1
        result = current_data["result"]
608 1
        assert len(result) == 2
609 1
        assert result[0][-1]['type'] == "incomplete"
610 1
        assert result[1][-1]['type'] == "incomplete"
611
612 1
    @patch("napps.amlight.sdntrace_cp.main.get_stored_flows")
613 1
    async def test_get_traces_untagged(self, mock_stored_flows, event_loop):
614
        """Test traces rest call."""
615 1
        self.napp.controller.loop = event_loop
616 1
        payload = [{
617
            "trace": {
618
                "switch": {
619
                    "dpid": "00:00:00:00:00:00:00:01",
620
                    "in_port": 1
621
                    },
622
                "eth": {"dl_vlan": 10},
623
            }
624
        }, {
625
            "trace": {
626
                "switch": {
627
                    "dpid": "00:00:00:00:00:00:00:01",
628
                    "in_port": 1
629
                    }
630
            }
631
        }
632
        ]
633
634 1
        stored_flow1 = {
635
            "flow": {
636
                "match": {"dl_vlan": 0, "in_port": 1},
637
                "actions": [
638
                    {"action_type": "pop_vlan"},
639
                    {"action_type": "output", "port": 2},
640
                ],
641
            }
642
        }
643 1
        stored_flow2 = {
644
            "flow": {
645
                "match": {"in_port": 1},
646
                "actions": [
647
                    {"action_type": "pop_vlan"},
648
                    {"action_type": "output", "port": 3},
649
                ],
650
            }
651
        }
652 1
        stored_flow3 = {
653
            "flow": {
654
                "match": {"dl_vlan": 10, "in_port": 1},
655
                "actions": [
656
                    {"action_type": "pop_vlan"},
657
                    {"action_type": "output", "port": 1},
658
                ],
659
            }
660
        }
661 1
        mock_stored_flows.return_value = {
662
            "00:00:00:00:00:00:00:01": [
663
                stored_flow1,
664
                stored_flow2,
665
                stored_flow3
666
            ]
667
        }
668
669 1
        resp = await self.api_client.put(self.traces_endpoint, json=payload)
670 1
        assert resp.status_code == 200
671 1
        current_data = resp.json()
672
673 1
        result = current_data["result"]
674 1
        assert result[0][0]["type"] == "last"
675 1
        assert result[0][0]["out"] == {"port": 3}
676 1
        assert result[1][0]["type"] == "last"
677 1
        assert result[1][0]["out"] == {"port": 2}
678
679 1
        mock_stored_flows.return_value = {
680
            "00:00:00:00:00:00:00:01": [
681
                stored_flow3,
682
                stored_flow2,
683
                stored_flow1
684
            ]
685
        }
686
687 1
        resp = await self.api_client.put(self.traces_endpoint, json=payload)
688 1
        assert resp.status_code == 200
689 1
        current_data = resp.json()
690 1
        result = current_data["result"]
691 1
        assert result[0][0]["type"] == "loop"
692 1
        assert result[0][0]["out"] == {"port": 1}
693 1
        assert result[1][0]["type"] == "last"
694 1
        assert result[1][0]["out"] == {"port": 3}
695
696 1
    @patch("napps.amlight.sdntrace_cp.main.get_stored_flows")
697 1
    async def test_get_traces_any(self, mock_stored_flows, event_loop):
698
        """Test traces rest call."""
699 1
        self.napp.controller.loop = event_loop
700 1
        payload = [{
701
            "trace": {
702
                "switch": {
703
                    "dpid": "00:00:00:00:00:00:00:01",
704
                    "in_port": 1
705
                    },
706
                "eth": {"dl_vlan": 10}
707
            }
708
        }, {
709
            "trace": {
710
                "switch": {
711
                    "dpid": "00:00:00:00:00:00:00:01",
712
                    "in_port": 1
713
                    }
714
            }
715
        }
716
        ]
717
718 1
        stored_flow1 = {
719
            "flow": {
720
                "match": {"dl_vlan": "4096/4096", "in_port": 1},
721
                "actions": [
722
                    {"action_type": "pop_vlan"},
723
                    {"action_type": "output", "port": 2},
724
                ],
725
            }
726
        }
727 1
        stored_flow2 = {
728
            "flow": {
729
                "match": {"dl_vlan": 10, "in_port": 1},
730
                "actions": [
731
                    {"action_type": "pop_vlan"},
732
                    {"action_type": "output", "port": 1},
733
                ],
734
            }
735
        }
736 1
        stored_flow3 = {
737
            "flow": {
738
                "match": {"dl_vlan": "10/10", "in_port": 1},
739
                "actions": [
740
                    {"action_type": "pop_vlan"},
741
                    {"action_type": "output", "port": 3},
742
                ],
743
            }
744
        }
745 1
        stored_flow4 = {
746
            "flow": {
747
                "match": {"dl_vlan": "20/10", "in_port": 1},
748
                "actions": [
749
                    {"action_type": "pop_vlan"},
750
                    {"action_type": "output", "port": 1},
751
                ],
752
            }
753
        }
754 1
        mock_stored_flows.return_value = {
755
            "00:00:00:00:00:00:00:01": [
756
                stored_flow1,
757
                stored_flow2,
758
                stored_flow3,
759
                stored_flow4
760
            ]
761
        }
762
763 1
        resp = await self.api_client.put(self.traces_endpoint, json=payload)
764 1
        assert resp.status_code == 200
765 1
        current_data = resp.json()
766 1
        result = current_data["result"]
767 1
        assert result[0][0]["type"] == "last"
768 1
        assert result[0][0]["out"] == {"port": 2}
769 1
        assert result[1][0]["type"] == "incomplete"
770 1
        assert result[1][0]["out"] is None
771
772 1
        mock_stored_flows.return_value = {
773
            "00:00:00:00:00:00:00:01": [
774
                stored_flow4,
775
                stored_flow3,
776
                stored_flow2,
777
                stored_flow1
778
            ]
779
        }
780
781 1
        resp = await self.api_client.put(self.traces_endpoint, json=payload)
782 1
        assert resp.status_code == 200
783 1
        current_data = resp.json()
784 1
        result = current_data["result"]
785 1
        assert result[0][0]["type"] == "last"
786 1
        assert result[0][0]["out"] == {"port": 3}
787 1
        assert result[1][0]["type"] == "incomplete"
788 1
        assert result[1][0]["out"] is None
789
790 1
    @pytest.mark.parametrize(
791
        "flow,args,match",
792
        [
793
            (
794
                {'flow': {'match': {'dl_vlan': 10}}},
795
                {'dl_vlan': [10]},
796
                {'flow': {'match': {'dl_vlan': 10}}},
797
            ),
798
            (
799
                {'flow': {'match': {'dl_vlan': 0}}},
800
                {},
801
                {'flow': {'match': {'dl_vlan': 0}}},
802
            ),
803
            (
804
                {'flow': {'match': {'dl_vlan': '10/10'}}},
805
                {'dl_vlan': [10]},
806
                {'flow': {'match': {'dl_vlan': '10/10'}}},
807
            ),
808
            (
809
                {'flow': {'match': {'dl_vlan': '10/10'}}},
810
                {'dl_vlan': [2]},
811
                False,
812
            ),
813
            (
814
                {'flow': {'match': {
815
                                    'nw_src': '192.168.20.21/10',
816
                                    'nw_dst': '192.168.20.21/32',
817
                                    'ipv6_src': '2002:db8::8a3f:362:7897/10',
818
                                    'ipv6_dst': '2002:db8::8a3f:362:7897/128',
819
                                    }
820
                          }
821
                 },
822
                {
823
                        'nw_src': '192.168.20.21',
824
                        'nw_dst': '192.168.20.21',
825
                        'ipv6_src': '2002:db8::8a3f:362:7897',
826
                        'ipv6_dst': '2002:db8::8a3f:362:7897',
827
                },
828
                {'flow': {'match': {
829
                                    'nw_src': '192.168.20.21/10',
830
                                    'nw_dst': '192.168.20.21/32',
831
                                    'ipv6_src': '2002:db8::8a3f:362:7897/10',
832
                                    'ipv6_dst': '2002:db8::8a3f:362:7897/128',
833
                                    }
834
                          }
835
                 },
836
            ),
837
            (
838
                {'flow': {'match': {'nw_src': '192.168.20.21'}}},
839
                {'nw_src': '192.168.20.30'},
840
                False,
841
            ),
842
            (
843
                {'flow': {'match': {'ipv6_src': '2002:db8::8a3f:362:7'}}},
844
                {'ipv6_src': '2002:db8::8a3f:362:7897'},
845
                False,
846
            ),
847
            (
848
                {'flow': {'match': {'in_port': 1, 'dl_vlan': '4096/4096'}}},
849
                {'in_port': 1, 'dl_vlan': [1]},
850
                {'flow': {'match': {'in_port': 1, 'dl_vlan': '4096/4096'}}},
851
            ),
852
            (
853
                {'flow': {'match': {'in_port': 1, 'dl_vlan': '4096/4096'}}},
854
                {'dl_vlan': [1]},
855
                False,
856
            ),
857
        ],
858
    )
859 1
    def test_do_match(self, flow, args, match):
860
        """Test do_match."""
861 1
        assert self.napp.do_match(flow, args) == match
862
863 1
    def test_match_flows(self):
864
        """Test match_flows."""
865 1
        flow = {"flow": {"match": {"dl_vlan": "10/10", "in_port": 1}}}
866 1
        switch = get_switch_mock("00:00:00:00:00:00:00:01")
867 1
        stored_flows = {"00:00:00:00:00:00:00:01": [flow]}
868 1
        args = {"dl_vlan": [10], "in_port": 1}
869 1
        resp = self.napp.match_flows(switch, args, stored_flows)
870 1
        assert resp == [flow]
871
872 1
        stored_flows = {}
873 1
        resp = self.napp.match_flows(switch, args, stored_flows)
874 1
        assert not resp
875
876 1
    @pytest.mark.parametrize(
877
        "flow,args,resp",
878
        [
879
            (
880
                {"flow": {
881
                          "match": {"dl_vlan": "10/10", "in_port": 1},
882
                          "actions": [{'action_type': 'output', 'port': 1}]
883
                          }
884
                 },
885
                {"dl_vlan": [10], "in_port": 1},
886
                ({"flow": {
887
                            "match": {"dl_vlan": "10/10", "in_port": 1},
888
                            "actions": [{'action_type': 'output', 'port': 1}]
889
                            }
890
                  }, {"dl_vlan": [10], "in_port": 1}, 1),
891
            ),
892
            (
893
                {"flow": {
894
                          "match": {"dl_vlan": "10/10", "in_port": 1},
895
                          "actions": [{'action_type': 'push_vlan'}]
896
                          }
897
                 },
898
                {"dl_vlan": [10], "in_port": 1},
899
                ({"flow": {
900
                            "match": {"dl_vlan": "10/10", "in_port": 1},
901
                            "actions": [{'action_type': 'push_vlan'}]
902
                            }
903
                  }, {"dl_vlan": [10, 0], "in_port": 1}, None),
904
            ),
905
            (
906
                {"flow": {
907
                          "match": {"dl_vlan": "10/10", "in_port": 1},
908
                          "actions": [{'action_type': 'pop_vlan'}]
909
                          }
910
                 },
911
                {"dl_vlan": [10], "in_port": 1},
912
                ({"flow": {
913
                            "match": {"dl_vlan": "10/10", "in_port": 1},
914
                            "actions": [{'action_type': 'pop_vlan'}]
915
                            }
916
                  }, {"in_port": 1}, None),
917
            ),
918
            (
919
                {"flow": {
920
                          "match": {"dl_vlan": "10/10", "in_port": 1},
921
                          "actions": [{'action_type': 'set_vlan',
922
                                       'vlan_id': 2}]
923
                          }
924
                 },
925
                {"dl_vlan": [10], "in_port": 1},
926
                ({"flow": {
927
                            "match": {"dl_vlan": "10/10", "in_port": 1},
928
                            "actions": [{'action_type': 'set_vlan',
929
                                         'vlan_id': 2}]
930
                            }
931
                  }, {"dl_vlan": [2], "in_port": 1}, None),
932
            ),
933
        ],
934
    )
935 1
    def test_match_and_apply(self, flow, args, resp):
936
        """Test match_and_apply."""
937 1
        switch = get_switch_mock("00:00:00:00:00:00:00:01", 0x04)
938 1
        stored_flows = {"00:00:00:00:00:00:00:01": [flow]}
939 1
        assert self.napp.match_and_apply(switch, args, stored_flows) == resp
940
941 1
        stored_flows = {}
942 1
        resp = self.napp.match_and_apply(switch, args, stored_flows)
943 1
        assert not resp[0]
944
        assert not resp[2]
945