Passed
Pull Request — master (#95)
by
unknown
08:32 queued 05:44
created

TestMain.test_traces_fail()   A

Complexity

Conditions 1

Size

Total Lines 21
Code Lines 14

Duplication

Lines 21
Ratio 100 %

Importance

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