Passed
Pull Request — master (#129)
by Carlos
02:23
created

TestMain.test_event_add_flow_delete()   A

Complexity

Conditions 1

Size

Total Lines 14
Code Lines 13

Duplication

Lines 14
Ratio 100 %

Importance

Changes 0
Metric Value
cc 1
eloc 13
nop 2
dl 14
loc 14
rs 9.75
c 0
b 0
f 0
1
"""Test Main methods."""
2
from unittest import TestCase
3
from unittest.mock import MagicMock, patch
4
5
from kytos.lib.helpers import (get_connection_mock, get_controller_mock,
6
                               get_kytos_event_mock, get_switch_mock,
7
                               get_test_client)
8
9
10
# pylint: disable=protected-access, too-many-public-methods
11
class TestMain(TestCase):
12
    """Tests for the Main class."""
13
14
    API_URL = 'http://localhost:8181/api/kytos/flow_manager'
15
16
    def setUp(self):
17
        patch('kytos.core.helpers.run_on_thread', lambda x: x).start()
18
        # pylint: disable=import-outside-toplevel
19
        from napps.kytos.flow_manager.main import Main
20
21
        self.addCleanup(patch.stopall)
22
23
        controller = get_controller_mock()
24
        self.switch_01 = get_switch_mock("00:00:00:00:00:00:00:01", 0x04)
25
        self.switch_01.is_enabled.return_value = True
26
        self.switch_01.flows = []
27
28
        self.switch_02 = get_switch_mock("00:00:00:00:00:00:00:02", 0x04)
29
        self.switch_02.is_enabled.return_value = False
30
        self.switch_02.flows = []
31
32
        controller.switches = {"00:00:00:00:00:00:00:01": self.switch_01,
33
                               "00:00:00:00:00:00:00:02": self.switch_02}
34
35
        self.napp = Main(controller)
36
37
    def test_rest_list_without_dpid(self):
38
        """Test list rest method withoud dpid."""
39
        flow_dict = {
40
            "priority": 13,
41
            "cookie": 84114964,
42
            "command": "add",
43
            "match": {"dl_dst": "00:15:af:d5:38:98"},
44
        }
45
        flow_dict_2 = {
46
            "priority": 18,
47
            "cookie": 84114964,
48
            "command": "add",
49
            "match": {"dl_dst": "00:15:af:d5:38:98"},
50
        }
51
        flow_1 = MagicMock()
52
        flow_1.as_dict.return_value = flow_dict
53
        flow_2 = MagicMock()
54
        flow_2.as_dict.return_value = flow_dict_2
55
        self.switch_01.flows.append(flow_1)
56
        self.switch_02.flows.append(flow_2)
57
58
        api = get_test_client(self.napp.controller, self.napp)
59
        url = f'{self.API_URL}/v2/flows'
60
61
        response = api.get(url)
62
        expected = {
63
            '00:00:00:00:00:00:00:01': {'flows': [flow_dict]},
64
            '00:00:00:00:00:00:00:02': {'flows': [flow_dict_2]},
65
        }
66
        self.assertEqual(response.json, expected)
67
        self.assertEqual(response.status_code, 200)
68
69
    def test_rest_list_with_dpid(self):
70
        """Test list rest method with dpid."""
71
        flow_dict = {
72
            "priority": 13,
73
            "cookie": 84114964,
74
            "command": "add",
75
            "match": {"dl_dst": "00:15:af:d5:38:98"},
76
        }
77
        flow_1 = MagicMock()
78
        flow_1.as_dict.return_value = flow_dict
79
        self.switch_01.flows.append(flow_1)
80
81
        api = get_test_client(self.napp.controller, self.napp)
82
        url = f'{self.API_URL}/v2/flows/00:00:00:00:00:00:00:01'
83
84
        response = api.get(url)
85
        expected = {'00:00:00:00:00:00:00:01': {'flows': [flow_dict]}}
86
87
        self.assertEqual(response.json, expected)
88
        self.assertEqual(response.status_code, 200)
89
90
    @patch('napps.kytos.flow_manager.main.Main._install_flows')
91
    def test_rest_add_and_delete_without_dpid(self, mock_install_flows):
92
        """Test add and delete rest method without dpid."""
93
        api = get_test_client(self.napp.controller, self.napp)
94
95
        for method in ['flows', 'delete']:
96
            url = f'{self.API_URL}/v2/{method}'
97
98
            response_1 = api.post(url, json={'data': '123'})
99
            response_2 = api.post(url)
100
101
            self.assertEqual(response_1.status_code, 200)
102
            self.assertEqual(response_2.status_code, 404)
103
104
        self.assertEqual(mock_install_flows.call_count, 2)
105
106
    @patch('napps.kytos.flow_manager.main.Main._install_flows')
107
    def test_rest_add_and_delete_with_dpid(self, mock_install_flows):
108
        """Test add and delete rest method with dpid."""
109
        api = get_test_client(self.napp.controller, self.napp)
110
111
        for method in ['flows', 'delete']:
112
            url_1 = f'{self.API_URL}/v2/{method}/00:00:00:00:00:00:00:01'
113
            url_2 = f'{self.API_URL}/v2/{method}/00:00:00:00:00:00:00:02'
114
            url_3 = f'{self.API_URL}/v2/{method}/00:00:00:00:00:00:00:03'
115
116
            response_1 = api.post(url_1)
117
            response_2 = api.post(url_1, json={'data': '123'})
118
            response_3 = api.post(url_2, json={'data': '123'})
119
            response_4 = api.post(url_3, json={'data': '123'})
120
121
            self.assertEqual(response_1.status_code, 404)
122
            self.assertEqual(response_2.status_code, 200)
123
            if method == 'flows':
124
                self.assertEqual(response_3.status_code, 404)
125
            else:
126
                self.assertEqual(response_3.status_code, 200)
127
            self.assertEqual(response_4.status_code, 404)
128
129
        self.assertEqual(mock_install_flows.call_count, 3)
130
131
    def test_get_all_switches_enabled(self):
132
        """Test _get_all_switches_enabled method."""
133
        switches = self.napp._get_all_switches_enabled()
134
135
        self.assertEqual(switches, [self.switch_01])
136
137 View Code Duplication
    @patch('napps.kytos.flow_manager.main.Main._store_changed_flows')
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
138
    @patch('napps.kytos.flow_manager.main.Main._send_napp_event')
139
    @patch('napps.kytos.flow_manager.main.Main._add_flow_mod_sent')
140
    @patch('napps.kytos.flow_manager.main.Main._send_flow_mod')
141
    @patch('napps.kytos.flow_manager.main.FlowFactory.get_class')
142
    def test_install_flows(self, *args):
143
        """Test _install_flows method."""
144
        (mock_flow_factory, mock_send_flow_mod, mock_add_flow_mod_sent,
145
         mock_send_napp_event, _) = args
146
        serializer = MagicMock()
147
        flow = MagicMock()
148
        flow_mod = MagicMock()
149
150
        flow.as_of_add_flow_mod.return_value = flow_mod
151
        serializer.from_dict.return_value = flow
152
        mock_flow_factory.return_value = serializer
153
154
        flows_dict = {'flows': [MagicMock()]}
155
        switches = [self.switch_01]
156
        self.napp._install_flows('add', flows_dict, switches)
157
158
        mock_send_flow_mod.assert_called_with(flow.switch, flow_mod)
159
        mock_add_flow_mod_sent.assert_called_with(flow_mod.header.xid,
160
                                                  flow, 'add')
161
        mock_send_napp_event.assert_called_with(self.switch_01, flow, 'add')
162
163 View Code Duplication
    @patch('napps.kytos.flow_manager.main.Main._store_changed_flows')
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
164
    @patch('napps.kytos.flow_manager.main.Main._send_napp_event')
165
    @patch('napps.kytos.flow_manager.main.Main._add_flow_mod_sent')
166
    @patch('napps.kytos.flow_manager.main.Main._send_flow_mod')
167
    @patch('napps.kytos.flow_manager.main.FlowFactory.get_class')
168
    def test_install_flows_with_delete_strict(self, *args):
169
        """Test _install_flows method with strict delete command."""
170
        (mock_flow_factory, mock_send_flow_mod, mock_add_flow_mod_sent,
171
         mock_send_napp_event, _) = args
172
        serializer = MagicMock()
173
        flow = MagicMock()
174
        flow_mod = MagicMock()
175
176
        flow.as_of_strict_delete_flow_mod.return_value = flow_mod
177
        serializer.from_dict.return_value = flow
178
        mock_flow_factory.return_value = serializer
179
180
        flows_dict = {'flows': [MagicMock()]}
181
        switches = [self.switch_01]
182
        self.napp._install_flows('delete_strict', flows_dict, switches)
183
184
        mock_send_flow_mod.assert_called_with(flow.switch, flow_mod)
185
        mock_add_flow_mod_sent.assert_called_with(flow_mod.header.xid,
186
                                                  flow, 'delete_strict')
187
        mock_send_napp_event.assert_called_with(self.switch_01, flow,
188
                                                'delete_strict')
189
190 View Code Duplication
    @patch('napps.kytos.flow_manager.main.Main._install_flows')
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
191
    def test_event_add_flow(self, mock_install_flows):
192
        """Test method for installing flows on the switches through events."""
193
        dpid = "00:00:00:00:00:00:00:01"
194
        switch = get_switch_mock(dpid)
195
        self.napp.controller.switches = {dpid: switch}
196
        mock_flow_dict = MagicMock()
197
        event = get_kytos_event_mock(name='kytos.flow_manager.flows.install',
198
                                     content={'dpid': dpid,
199
                                              'command': 'add',
200
                                              'flow_dict': mock_flow_dict})
201
        self.napp.event_add_flow(event)
202
        mock_install_flows.assert_called_with('add', mock_flow_dict, [switch])
203
204 View Code Duplication
    @patch('napps.kytos.flow_manager.main.Main._install_flows')
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
205
    def test_event_add_flow_delete(self, mock_install_flows):
206
        """Test method for removing flows on the switches through events."""
207
        dpid = "00:00:00:00:00:00:00:01"
208
        switch = get_switch_mock(dpid)
209
        self.napp.controller.switches = {dpid: switch}
210
        mock_flow_dict = MagicMock()
211
        event = get_kytos_event_mock(name='kytos.flow_manager.flows.delete',
212
                                     content={'dpid': dpid,
213
                                              'command': 'delete',
214
                                              'flow_dict': mock_flow_dict})
215
        self.napp.event_add_flow(event)
216
        mock_install_flows.assert_called_with('delete', mock_flow_dict,
217
                                              [switch])
218
219
    def test_add_flow_mod_sent(self):
220
        """Test _add_flow_mod_sent method."""
221
        xid = 0
222
        flow = MagicMock()
223
224
        self.napp._add_flow_mod_sent(xid, flow, 'add')
225
226
        self.assertEqual(self.napp._flow_mods_sent[xid], (flow, 'add'))
227
228
    @patch('kytos.core.buffers.KytosEventBuffer.put')
229
    def test_send_flow_mod(self, mock_buffers_put):
230
        """Test _send_flow_mod method."""
231
        switch = get_switch_mock("00:00:00:00:00:00:00:01", 0x04)
232
        flow_mod = MagicMock()
233
234
        self.napp._send_flow_mod(switch, flow_mod)
235
236
        mock_buffers_put.assert_called()
237
238
    @patch('kytos.core.buffers.KytosEventBuffer.put')
239
    def test_send_napp_event(self, mock_buffers_put):
240
        """Test _send_napp_event method."""
241
        switch = get_switch_mock("00:00:00:00:00:00:00:01", 0x04)
242
        flow = MagicMock()
243
244
        for command in ['add', 'delete', 'delete_strict', 'error']:
245
            self.napp._send_napp_event(switch, flow, command)
246
247
        self.assertEqual(mock_buffers_put.call_count, 4)
248
249
    @patch('napps.kytos.flow_manager.main.Main._send_napp_event')
250
    def test_handle_errors(self, mock_send_napp_event):
251
        """Test handle_errors method."""
252
        flow = MagicMock()
253
        self.napp._flow_mods_sent[0] = (flow, 'add')
254
255
        switch = get_switch_mock("00:00:00:00:00:00:00:01")
256
        switch.connection = get_connection_mock(
257
            0x04, get_switch_mock("00:00:00:00:00:00:00:02"))
258
259
        protocol = MagicMock()
260
        protocol.unpack.return_value = 'error_packet'
261
262
        switch.connection.protocol = protocol
263
264
        message = MagicMock()
265
        message.header.xid.value = 0
266
        message.error_type = 2
267
        message.code = 5
268
        event = get_kytos_event_mock(name='.*.of_core.*.ofpt_error',
269
                                     content={'message': message,
270
                                              'source': switch.connection})
271
        self.napp.handle_errors(event)
272
273
        mock_send_napp_event.assert_called_with(flow.switch, flow, 'error',
274
                                                error_command='add',
275
                                                error_code=5, error_type=2)
276
277
    @patch("napps.kytos.flow_manager.main.StoreHouse.get_data")
278
    def test_load_flows(self, mock_storehouse):
279
        """Test load flows."""
280
        self.napp._load_flows()
281
        mock_storehouse.assert_called()
282
283
    @patch("napps.kytos.flow_manager.main.CONSISTENCY_INTERVAL", -1)
284
    @patch("napps.kytos.flow_manager.main.Main._install_flows")
285
    def test_resend_stored_flows(self, mock_install_flows):
286
        """Test resend stored flows."""
287
        dpid = "00:00:00:00:00:00:00:01"
288
        switch = get_switch_mock(dpid, 0x04)
289
        mock_event = MagicMock()
290
        flow = {"command": "add", "flow": MagicMock()}
291
292
        flows = {"flow_list": [flow]}
293
        mock_event.content = {"switch": switch}
294
        self.napp.controller.switches = {dpid: switch}
295
        self.napp.stored_flows = {dpid: flows}
296
        self.napp.resend_stored_flows(mock_event)
297
        mock_install_flows.assert_called()
298
299
    @patch("napps.kytos.of_core.flow.FlowFactory.get_class")
300
    @patch("napps.kytos.flow_manager.main.StoreHouse.save_flow")
301
    def test_store_changed_flows(self, mock_save_flow, _):
302
        """Test store changed flows."""
303
        dpid = "00:00:00:00:00:00:00:01"
304
        switch = get_switch_mock(dpid, 0x04)
305
        switch.id = dpid
306
        flow = {
307
            "priority": 17,
308
            "cookie": 84114964,
309
            "command": "add",
310
            "match": {"dl_dst": "00:15:af:d5:38:98"},
311
        }
312
        match_fields = {
313
            "priority": 17,
314
            "cookie": 84114964,
315
            "command": "add",
316
            "dl_dst": "00:15:af:d5:38:98",
317
        }
318
        flows = {"flow": flow}
319
320
        command = "add"
321
        flow_list = {
322
            "flow_list": [
323
                {"match_fields": match_fields, "command": "delete",
324
                 "flow": flow}
325
            ]
326
        }
327
        self.napp.stored_flows = {dpid: flow_list}
328
        self.napp._store_changed_flows(command, flows, switch)
329
        mock_save_flow.assert_called()
330
331
        self.napp.stored_flows = {}
332
        self.napp._store_changed_flows(command, flows, switch)
333
        mock_save_flow.assert_called()
334
335 View Code Duplication
    @patch('napps.kytos.flow_manager.main.Main._install_flows')
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
336
    @patch('napps.kytos.flow_manager.main.FlowFactory.get_class')
337
    def test_check_switch_consistency_add(self, *args):
338
        """Test check_switch_consistency method.
339
340
        This test checks the case when a flow is missing in switch and have the
341
        ADD command.
342
        """
343
        (mock_flow_factory, mock_install_flows) = args
344
        dpid = "00:00:00:00:00:00:00:01"
345
        switch = get_switch_mock(dpid, 0x04)
346
        switch.flows = []
347
348
        flow_1 = MagicMock()
349
        flow_1.as_dict.return_value = {'flow_1': 'data'}
350
351
        flow_list = [{"command": "add",
352
                      "flow": {'flow_1': 'data'}
353
                      }]
354
        serializer = MagicMock()
355
356
        mock_flow_factory.return_value = serializer
357
        self.napp.stored_flows = {dpid: {"flow_list": flow_list}}
358
        self.napp.check_switch_consistency(switch)
359
        mock_install_flows.assert_called()
360
361 View Code Duplication
    @patch('napps.kytos.flow_manager.main.Main._install_flows')
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
362
    @patch('napps.kytos.flow_manager.main.FlowFactory.get_class')
363
    def test_check_switch_consistency_delete(self, *args):
364
        """Test check_switch_consistency method.
365
366
        This test checks the case when a flow is missing in switch and have the
367
        DELETE command.
368
        """
369
        (mock_flow_factory, mock_install_flows) = args
370
        dpid = "00:00:00:00:00:00:00:01"
371
        switch = get_switch_mock(dpid, 0x04)
372
373
        flow_1 = MagicMock()
374
        flow_1.as_dict.return_value = {'flow_1': 'data'}
375
376
        flow_list = [{"command": "delete",
377
                      "flow": {'flow_1': 'data'}
378
                      }]
379
        serializer = MagicMock()
380
        serializer.from_dict.return_value = flow_1
381
382
        switch.flows = [flow_1]
383
384
        mock_flow_factory.return_value = serializer
385
        self.napp.stored_flows = {dpid: {"flow_list": flow_list}}
386
        self.napp.check_switch_consistency(switch)
387
        mock_install_flows.assert_called()
388
389 View Code Duplication
    @patch('napps.kytos.flow_manager.main.Main._install_flows')
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
390
    @patch('napps.kytos.flow_manager.main.FlowFactory.get_class')
391
    def test_check_storehouse_consistency(self, *args):
392
        """Test check_storehouse_consistency method.
393
394
        This test checks the case when a flow is missing in storehouse.
395
        """
396
        (mock_flow_factory, mock_install_flows) = args
397
        dpid = "00:00:00:00:00:00:00:01"
398
        switch = get_switch_mock(dpid, 0x04)
399
400
        flow_1 = MagicMock()
401
        flow_1.as_dict.return_value = {'flow_1': 'data'}
402
403
        switch.flows = [flow_1]
404
405
        flow_list = [{"command": "add",
406
                      "flow": {'flow_2': 'data'}
407
                      }]
408
        serializer = MagicMock()
409
410
        mock_flow_factory.return_value = serializer
411
        self.napp.stored_flows = {dpid: {"flow_list": flow_list}}
412
        self.napp.check_storehouse_consistency(switch)
413
        mock_install_flows.assert_called()
414
415 View Code Duplication
    @patch('napps.kytos.flow_manager.main.Main._install_flows')
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
416
    @patch('napps.kytos.flow_manager.main.FlowFactory.get_class')
417
    @patch("napps.kytos.flow_manager.main.StoreHouse.save_flow")
418
    def test_no_strict_delete(self, *args):
419
        """Test the non-strict matching method.
420
421
        Test non-strict matching to delete a Flow using a cookie.
422
        """
423
        (mock_save_flow, _, _) = args
424
        dpid = "00:00:00:00:00:00:00:01"
425
        switch = get_switch_mock(dpid, 0x04)
426
        switch.id = dpid
427
        stored_flow = {
428
            "command": "add",
429
            "flow": {
430
                "actions": [{"action_type": "set_vlan", "vlan_id": 300}],
431
                "cookie": 6191162389751548793,
432
                "match": {"dl_vlan": 300, "in_port": 1},
433
            },
434
        }
435
        stored_flow2 = {
436
            "command": "add",
437
            "flow": {
438
                "actions": [],
439
                "cookie": 4961162389751548787,
440
                "match": {"in_port": 2},
441
            },
442
        }
443
        flow_to_install = {
444
            "cookie": 6191162389751548793,
445
            "cookie_mask": 18446744073709551615,
446
        }
447
        flow_list = {"flow_list": [stored_flow, stored_flow2]}
448
        command = "delete"
449
        self.napp.stored_flows = {dpid: flow_list}
450
451
        self.napp._store_changed_flows(command, flow_to_install, switch)
452
        mock_save_flow.assert_called()
453
        self.assertEqual(len(self.napp.stored_flows), 1)
454
455 View Code Duplication
    @patch('napps.kytos.flow_manager.main.Main._install_flows')
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
456
    @patch('napps.kytos.flow_manager.main.FlowFactory.get_class')
457
    @patch("napps.kytos.flow_manager.main.StoreHouse.save_flow")
458
    def test_no_strict_delete_with_ipv4(self, *args):
459
        """Test the non-strict matching method.
460
461
        Test non-strict matching to delete a Flow using IPv4.
462
        """
463
        (mock_save_flow, _, _) = args
464
        dpid = "00:00:00:00:00:00:00:01"
465
        switch = get_switch_mock(dpid, 0x04)
466
        switch.id = dpid
467
        stored_flow = {
468
            "command": "add",
469
            "flow": {
470
                "priority": 10,
471
                "cookie": 84114904,
472
                "match": {
473
                    "ipv4_src": "192.168.1.120",
474
                    "ipv4_dst": "192.168.0.2",
475
                },
476
                "actions": [],
477
            },
478
        }
479
        stored_flow2 = {
480
            "command": "add",
481
            "flow": {
482
                "actions": [],
483
                "cookie": 4961162389751548787,
484
                "match": {"in_port": 2},
485
            },
486
        }
487
        flow_to_install = {"match": {"ipv4_src": '192.168.1.1/24'}}
488
        flow_list = {"flow_list": [stored_flow, stored_flow2]}
489
        command = "delete"
490
        self.napp.stored_flows = {dpid: flow_list}
491
492
        self.napp._store_changed_flows(command, flow_to_install, switch)
493
        mock_save_flow.assert_called()
494
        self.assertEqual(len(self.napp.stored_flows[dpid]['flow_list']), 2)
495
496 View Code Duplication
    @patch('napps.kytos.flow_manager.main.Main._install_flows')
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
497
    @patch('napps.kytos.flow_manager.main.FlowFactory.get_class')
498
    @patch("napps.kytos.flow_manager.main.StoreHouse.save_flow")
499
    def test_no_strict_delete_with_ipv4_fail(self, *args):
500
        """Test the non-strict matching method.
501
502
        Test non-strict Fail case matching to delete a Flow using IPv4.
503
        """
504
        (mock_save_flow, _, _) = args
505
        dpid = "00:00:00:00:00:00:00:01"
506
        switch = get_switch_mock(dpid, 0x04)
507
        switch.id = dpid
508
        stored_flow = {
509
            "command": "add",
510
            "flow": {
511
                "priority": 10,
512
                "cookie": 84114904,
513
                "match": {
514
                    "ipv4_src": "192.168.2.1",
515
                    "ipv4_dst": "192.168.0.2",
516
                },
517
                "actions": [],
518
            },
519
        }
520
        stored_flow2 = {
521
            "command": "add",
522
            "flow": {
523
                "actions": [],
524
                "cookie": 4961162389751548787,
525
                "match": {"in_port": 2},
526
            },
527
        }
528
        flow_to_install = {"match": {"ipv4_src": '192.168.1.1/24'}}
529
        flow_list = {"flow_list": [stored_flow, stored_flow2]}
530
        command = "delete"
531
        self.napp.stored_flows = {dpid: flow_list}
532
533
        self.napp._store_changed_flows(command, flow_to_install, switch)
534
        mock_save_flow.assert_called()
535
        self.assertEqual(len(self.napp.stored_flows[dpid]['flow_list']), 3)
536
537
    @patch('napps.kytos.flow_manager.main.Main._install_flows')
538
    @patch('napps.kytos.flow_manager.main.FlowFactory.get_class')
539
    @patch("napps.kytos.flow_manager.main.StoreHouse.save_flow")
540
    def test_no_strict_delete_of10(self, *args):
541
        """Test the non-strict matching method.
542
543
        Test non-strict matching to delete a Flow using OF10.
544
        """
545
        (mock_save_flow, _, _) = args
546
        dpid = "00:00:00:00:00:00:00:01"
547
        switch = get_switch_mock(dpid, 0x01)
548
        switch.id = dpid
549
        stored_flow = {
550
            "command": "add",
551
            "flow": {
552
                "actions": [{"max_len": 65535, "port": 6}],
553
                "cookie": 4961162389751548787,
554
                "match": {
555
                    "in_port": 80,
556
                    "dl_src": "00:00:00:00:00:00",
557
                    "dl_dst": "f2:0b:a4:7d:f8:ea",
558
                    "dl_vlan": 0,
559
                    "dl_vlan_pcp": 0,
560
                    "dl_type": 0,
561
                    "nw_tos": 0,
562
                    "nw_proto": 0,
563
                    "nw_src": "192.168.0.1",
564
                    "nw_dst": "0.0.0.0",
565
                    "tp_src": 0,
566
                    "tp_dst": 0,
567
                },
568
                "out_port": 65532,
569
                "priority": 123,
570
            },
571
        }
572
        stored_flow2 = {
573
            "command": "add",
574
            "flow": {
575
                "actions": [],
576
                "cookie": 4961162389751654,
577
                "match": {
578
                    "in_port": 2,
579
                    "dl_src": "00:00:00:00:00:00",
580
                    "dl_dst": "f2:0b:a4:7d:f8:ea",
581
                    "dl_vlan": 0,
582
                    "dl_vlan_pcp": 0,
583
                    "dl_type": 0,
584
                    "nw_tos": 0,
585
                    "nw_proto": 0,
586
                    "nw_src": "192.168.0.1",
587
                    "nw_dst": "0.0.0.0",
588
                    "tp_src": 0,
589
                    "tp_dst": 0,
590
                },
591
                "out_port": 655,
592
                "priority": 1,
593
            },
594
        }
595
        flow_to_install = {"match": {"in_port": 80, "wildcards": 4194303}}
596
        flow_list = {"flow_list": [stored_flow, stored_flow2]}
597
        command = "delete"
598
        self.napp.stored_flows = {dpid: flow_list}
599
600
        self.napp._store_changed_flows(command, flow_to_install, switch)
601
        mock_save_flow.assert_called()
602
        self.assertEqual(len(self.napp.stored_flows[dpid]['flow_list']), 1)
603