Passed
Pull Request — master (#76)
by
unknown
03:41
created

build.tests.unit.test_main.TestMain.test_execute()   A

Complexity

Conditions 1

Size

Total Lines 16
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 14
dl 0
loc 16
rs 9.7
c 0
b 0
f 0
cc 1
nop 2
1
"""Test Main methods."""
2
from unittest import TestCase
3
from unittest.mock import MagicMock, create_autospec, patch, PropertyMock
4
5
from pyof.foundation.network_types import Ethernet
6
from pyof.v0x01.controller2switch.common import StatsType
7
from pyof.v0x04.controller2switch.common import MultipartType
8
9
from kytos.core.connection import ConnectionState
10
from kytos.lib.helpers import (get_switch_mock, get_kytos_event_mock,
11
                               get_connection_mock)
12
13
from tests.helpers import get_controller_mock
14
15
16
# pylint: disable=protected-access, too-many-public-methods
17
class TestMain(TestCase):
18
    """Test the Main class."""
19
20
    def setUp(self):
21
        """Execute steps before each tests.
22
        Set the server_name_url from kytos/of_core
23
        """
24
        self.switch_v0x01 = get_switch_mock("00:00:00:00:00:00:00:01", "v0x01")
25
        self.switch_v0x04 = get_switch_mock("00:00:00:00:00:00:00:02", "v0x04")
26
        self.switch_v0x01.connection = get_connection_mock(
27
            0x01, get_switch_mock("00:00:00:00:00:00:00:03"))
28
        self.switch_v0x04.connection = get_connection_mock(
29
            0x04, get_switch_mock("00:00:00:00:00:00:00:04"))
30
31
        patch('kytos.core.helpers.run_on_thread', lambda x: x).start()
32
        # pylint: disable=bad-option-value
33
        from napps.kytos.of_core.main import Main
34
        self.addCleanup(patch.stopall)
35
36
        self.napp = Main(get_controller_mock())
37
38
    @patch('napps.kytos.of_core.v0x01.utils.send_echo')
39
    @patch('napps.kytos.of_core.v0x04.utils.send_echo')
40
    def test_execute(self, *args):
41
        """Test execute."""
42
        (mock_of_core_v0x04_utils, mock_of_core_v0x01_utils) = args
43
        self.switch_v0x01.is_connected.return_value = True
44
        self.switch_v0x04.is_connected.return_value = True
45
        self.napp.controller.switches = {"00:00:00:00:00:00:00:01":
46
                                         self.switch_v0x01}
47
        self.napp.execute()
48
        mock_of_core_v0x01_utils.assert_called()
49
50
        self.napp.controller.switches = {"00:00:00:00:00:00:00:01":
51
                                         self.switch_v0x04}
52
        self.napp.execute()
53
        mock_of_core_v0x04_utils.assert_called()
54
55
    @patch('napps.kytos.of_core.v0x04.utils.update_flow_list')
56
    @patch('napps.kytos.of_core.v0x01.utils.update_flow_list')
57
    def test_request_flow_list(self, *args):
58
        """Test request flow list."""
59
        (mock_update_flow_list_v0x01, mock_update_flow_list_v0x04) = args
60
        mock_update_flow_list_v0x04.return_value = "ABC"
61
        self.napp._request_flow_list(self.switch_v0x01)
62
        mock_update_flow_list_v0x01.assert_called_with(self.napp.controller,
63
                                                       self.switch_v0x01)
64
        self.napp._request_flow_list(self.switch_v0x04)
65
        mock_update_flow_list_v0x04.assert_called_with(self.napp.controller,
66
                                                       self.switch_v0x04)
67
68
    @patch('napps.kytos.of_core.v0x01.flow.Flow.from_of_flow_stats')
69
    def test_handle_stats_reply(self, mock_from_of_flow_stats_v0x01):
70
        """Test handle stats reply."""
71
        mock_from_of_flow_stats_v0x01.return_value = "ABC"
72
73
        flow_msg = MagicMock()
74
        flow_msg.body = "A"
75
        flow_msg.body_type = StatsType.OFPST_FLOW
76
77
        name = 'kytos/of_core.v0x01.messages.in.ofpt_stats_reply'
78
        content = {"source": self.switch_v0x01.connection,
79
                   "message": flow_msg}
80
        event = get_kytos_event_mock(name=name, content=content)
81
        self.napp.handle_stats_reply(event)
82
        mock_from_of_flow_stats_v0x01.assert_called_with(
83
            flow_msg.body, self.switch_v0x01.connection.switch)
84
85
        desc_msg = MagicMock()
86
        desc_msg.body = "A"
87
        desc_msg.body_type = StatsType.OFPST_DESC
88
        content = {"source": self.switch_v0x01.connection,
89
                   "message": desc_msg}
90
        event = get_kytos_event_mock(name=name, content=content)
91
        switch_update = self.switch_v0x01.connection.switch.update_description
92
        self.napp.handle_stats_reply(event)
93
        self.assertEqual(switch_update.call_count, 1)
94
95
    @patch('napps.kytos.of_core.main.Main._handle_multipart_flow_stats')
96
    @patch('napps.kytos.of_core.v0x04.utils.handle_port_desc')
97
    def test_handle_multipart_reply(self, *args):
98
        """Test handle multipart reply."""
99
        (mock_of_core_v0x04_utils, mock_from_of_flow_stats_v0x04) = args
100
101
        flow_msg = MagicMock()
102
        flow_msg.multipart_type = MultipartType.OFPMP_FLOW
103
        name = 'kytos/of_core.v0x04.messages.in.ofpt_multipart_reply'
104
        content = {"source": self.switch_v0x04.connection,
105
                   "message": flow_msg}
106
        event = get_kytos_event_mock(name=name, content=content)
107
108
        self.napp.handle_multipart_reply(event)
109
        mock_from_of_flow_stats_v0x04.assert_called_with(
110
            flow_msg, self.switch_v0x04.connection.switch)
111
112
        ofpmp_port_desc = MagicMock()
113
        ofpmp_port_desc.body = "A"
114
        ofpmp_port_desc.multipart_type = MultipartType.OFPMP_PORT_DESC
115
        content = {"source": self.switch_v0x04.connection,
116
                   "message": ofpmp_port_desc}
117
        event = get_kytos_event_mock(name=name, content=content)
118
        self.napp.handle_multipart_reply(event)
119
        mock_of_core_v0x04_utils.assert_called_with(
120
            self.napp.controller, self.switch_v0x04.connection.switch,
121
            ofpmp_port_desc.body)
122
123
        ofpmp_desc = MagicMock()
124
        ofpmp_desc.body = "A"
125
        ofpmp_desc.multipart_type = MultipartType.OFPMP_DESC
126
        content = {"source": self.switch_v0x04.connection,
127
                   "message": ofpmp_desc}
128
        event = get_kytos_event_mock(name=name, content=content)
129
        switch_update = self.switch_v0x04.connection.switch.update_description
130
        self.napp.handle_multipart_reply(event)
131
        self.assertEqual(switch_update.call_count, 1)
132
133
    @patch('kytos.core.buffers.KytosEventBuffer.put')
134
    @patch('napps.kytos.of_core.v0x04.utils.send_set_config')
135
    @patch('napps.kytos.of_core.v0x01.utils.send_set_config')
136
    @patch('napps.kytos.of_core.v0x04.utils.send_desc_request')
137
    @patch('napps.kytos.of_core.v0x01.utils.send_desc_request')
138
    @patch('napps.kytos.of_core.v0x04.utils.handle_features_reply')
139
    @patch('napps.kytos.of_core.v0x01.utils.handle_features_reply')
140
    def test_handle_features_reply(self, *args):
141
        """Test handle features reply."""
142
        (mock_freply_v0x01, mock_freply_v0x04, mock_send_desc_request_v0x01,
143
         mock_send_desc_request_v0x04, mock_send_set_config_v0x01,
144
         mock_send_set_config_v0x04, mock_buffers_put) = args
145
        mock_freply_v0x01.return_value = self.switch_v0x01.connection.switch
146
        mock_freply_v0x04.return_value = self.switch_v0x04.connection.switch
147
148
        self.switch_v0x01.connection.state = ConnectionState.SETUP
149
        self.switch_v0x01.connection.protocol.state = 'waiting_features_reply'
150
        name = 'kytos/of_core.v0x0[14].messages.in.ofpt_features_reply'
151
        content = {"source": self.switch_v0x01.connection}
152
        event = get_kytos_event_mock(name=name, content=content)
153
        self.napp.handle_features_reply(event)
154
        mock_freply_v0x01.assert_called_with(self.napp.controller, event)
155
        mock_send_desc_request_v0x01.assert_called_with(
156
            self.napp.controller, self.switch_v0x01.connection.switch)
157
        mock_send_set_config_v0x01.assert_called_with(
158
            self.napp.controller, self.switch_v0x01.connection.switch)
159
160
        self.switch_v0x04.connection.state = ConnectionState.SETUP
161
        self.switch_v0x04.connection.protocol.state = 'waiting_features_reply'
162
        content = {"source": self.switch_v0x04.connection}
163
        event = get_kytos_event_mock(name=name, content=content)
164
        self.napp.handle_features_reply(event)
165
        mock_freply_v0x04.assert_called_with(self.napp.controller, event)
166
        mock_send_desc_request_v0x04.assert_called_with(
167
            self.napp.controller, self.switch_v0x04.connection.switch)
168
        mock_send_set_config_v0x04.assert_called_with(
169
            self.napp.controller, self.switch_v0x04.connection.switch)
170
171
        mock_buffers_put.assert_called()
172
173
    @patch('napps.kytos.of_core.main.Main._update_switch_flows')
174
    @patch('napps.kytos.of_core.v0x04.flow.Flow.from_of_flow_stats')
175
    @patch('napps.kytos.of_core.main.Main._is_multipart_reply_ours')
176
    def test_handle_multipart_flow_stats(self, *args):
177
        """Test handle multipart flow stats."""
178
        (mock_is_multipart_reply_ours, mock_from_of_flow_stats_v0x01,
179
         mock_update_switch_flows) = args
180
        mock_is_multipart_reply_ours.return_value = True
181
        mock_from_of_flow_stats_v0x01.return_value = "ABC"
182
183
        flow_msg = MagicMock()
184
        flow_msg.body = "A"
185
        flow_msg.flags.value = 2
186
        flow_msg.body_type = StatsType.OFPST_FLOW
187
188
        self.napp._handle_multipart_flow_stats(flow_msg, self.switch_v0x04)
189
190
        mock_is_multipart_reply_ours.assert_called_with(flow_msg,
191
                                                        self.switch_v0x04)
192
        mock_from_of_flow_stats_v0x01.assert_called_with(flow_msg.body,
193
                                                         self.switch_v0x04)
194
        mock_update_switch_flows.assert_called_with(self.switch_v0x04)
195
196
    def test_update_switch_flows(self):
197
        """Test update_switch_flows."""
198
        dpid = '00:00:00:00:00:00:00:01'
199
        mock_switch = get_switch_mock(dpid)
200
        mock_switch.id = dpid
201
        self.napp._multipart_replies_flows = {dpid: mock_switch}
202
        self.napp._multipart_replies_xids = {dpid: mock_switch}
203
        self.napp._update_switch_flows(mock_switch)
204
        self.assertEqual(self.napp._multipart_replies_xids, {})
205
        self.assertEqual(self.napp._multipart_replies_flows, {})
206
207
    def test_is_multipart_reply_ours(self):
208
        """Test _is_multipart_reply_ours."""
209
        dpid_a = '00:00:00:00:00:00:00:01'
210
        dpid_b = '00:00:00:00:00:00:00:02'
211
        mock_switch = get_switch_mock(dpid_a)
212
        mock_reply = MagicMock()
213
        mock_reply.header.xid = mock_switch
214
        type(mock_switch).id = PropertyMock(side_effect=[dpid_a,
215
                                            dpid_a, dpid_b])
216
        self.napp._multipart_replies_xids = {dpid_a: mock_switch}
217
        response = self.napp._is_multipart_reply_ours(mock_reply, mock_switch)
218
        self.assertEqual(response, True)
219
220
        response = self.napp._is_multipart_reply_ours(mock_reply, mock_switch)
221
        self.assertEqual(response, False)
222
223
    @patch('napps.kytos.of_core.main.of_slicer')
224
    @patch('napps.kytos.of_core.main.Main._negotiate')
225
    @patch('napps.kytos.of_core.main.Main.emit_message_in')
226
    def test_handle_raw_in(self, *args):
227
        """Test handle_raw_in."""
228
        (mock_emit_message_in, mock_negotiate, mock_of_slicer) = args
229
        mock_packets = MagicMock()
230
        mock_data = MagicMock()
231
        mock_connection = MagicMock()
232
        mock_connection.is_new.side_effect = [True, False]
233
        mock_connection.is_during_setup.return_value = False
234
        mock_of_slicer.return_value = [[mock_packets, mock_packets], mock_data]
235
        name = 'kytos/core.openflow.raw.in'
236
        content = {'source': mock_connection, 'new_data': mock_data}
237
        mock_event = get_kytos_event_mock(name=name, content=content)
238
239
        self.napp.handle_raw_in(mock_event)
240
        mock_negotiate.assert_called()
241
        mock_emit_message_in.assert_called()
242
243
    @patch('napps.kytos.of_core.main.Main.update_port_status')
244
    @patch('napps.kytos.of_core.main.Main.update_links')
245
    def test_emit_message_in(self, *args):
246
        """Test emit_message_in."""
247
        (mock_update_links, mock_update_port_status) = args
248
249
        mock_port_connection = MagicMock()
250
        msg_port_mock = MagicMock()
251
        msg_port_mock.header.message_type.name = 'ofpt_port_status'
252
        mock_port_connection.side_effect = True
253
        self.napp.emit_message_in(mock_port_connection,
254
                                  msg_port_mock)
255
        mock_update_port_status.assert_called_with(msg_port_mock,
256
                                                   mock_port_connection)
257
258
        mock_packet_in_connection = MagicMock()
259
        msg_packet_in_mock = MagicMock()
260
        mock_packet_in_connection.side_effect = True
261
        msg_packet_in_mock.header.message_type.name = 'ofpt_packet_in'
262
        self.napp.emit_message_in(mock_packet_in_connection,
263
                                  msg_packet_in_mock)
264
        mock_update_links.assert_called_with(msg_packet_in_mock,
265
                                             mock_packet_in_connection)
266
267
    @patch('napps.kytos.of_core.main.emit_message_out')
268
    def test_emit_message_out(self, mock_emit_message_out):
269
        """Test emit message_out"""
270
        mock_connection = MagicMock()
271
        mock_message = MagicMock()
272
        mock_connection.is_alive.return_value = True
273
        self.napp.emit_message_out(mock_connection, mock_message)
274
        mock_emit_message_out.assert_called()
275
276
    @patch('pyof.utils.v0x04.symmetric.echo_reply.EchoReply')
277
    @patch('napps.kytos.of_core.main.Main.emit_message_out')
278
    def test_handle_echo_request(self, *args):
279
        """Test handle echo request messages."""
280
        (mock_emit_message_out, mock_echo_reply) = args
281
        mock_event = MagicMock()
282
        mock_echo_request = MagicMock()
283
        mock_echo_reply.return_value = "A"
284
        mock_echo_request.header.xid = "A"
285
        mock_echo_request.data = "A"
286
        mock_event.source.protocol.version = 4
287
        mock_event.message = mock_echo_request
288
        self.napp.handle_echo_request(mock_event)
289
        mock_echo_reply.assert_called_with(xid=mock_echo_request.header.xid,
290
                                           data=mock_echo_request.data)
291
        mock_emit_message_out.assert_called_with(mock_event.source, "A")
292
293
    @patch('napps.kytos.of_core.main.Main.send_features_request')
294
    @patch('napps.kytos.of_core.v0x04.utils.say_hello')
295
    @patch('napps.kytos.of_core.main._get_version_from_bitmask')
296
    @patch('napps.kytos.of_core.main._get_version_from_header')
297
    def test_negotiate(self, *args):
298
        """Test negotiate."""
299
        (mock_version_header, mock_version_bitmask, mock_say_hello,
300
         mock_features_request) = args
301
        mock_version_header.return_value = 4
302
        mock_version_bitmask.return_value = 4
303
        mock_connection = MagicMock()
304
        mock_message = MagicMock()
305
        mock_message.versions = 4
306
        self.napp._negotiate(mock_connection, mock_message)
307
        mock_version_bitmask.assert_called_with(mock_message.versions)
308
        mock_say_hello.assert_called_with(self.napp.controller,
309
                                          mock_connection)
310
        mock_features_request.assert_called_with(mock_connection)
311
312
    @patch('pyof.utils.v0x04.asynchronous.error_msg.ErrorMsg')
313
    @patch('napps.kytos.of_core.main.Main.emit_message_out')
314
    @patch('kytos.core.buffers.KytosEventBuffer.put')
315
    def tests_fail_negotiation(self, *args):
316
        """Test fail_negotiation."""
317
        (mock_event_buffer, mock_emit_message_out,
318
         mock_error_msg) = args
319
        mock_connection = MagicMock()
320
        mock_message = MagicMock()
321
        mock_connection.id = "A"
322
        mock_message.side_effect = 4
323
        self.napp.fail_negotiation(mock_connection, mock_message)
324
        mock_event_buffer.assert_called()
325
        mock_emit_message_out.assert_called_with(mock_connection,
326
                                                 mock_error_msg.return_value)
327
328
    @patch('napps.kytos.of_core.settings.SEND_FEATURES_REQUEST_ON_ECHO')
329
    @patch('napps.kytos.of_core.main.Main.send_features_request')
330
    def test_handle_queued_openflow_echo_reply(self, *args):
331
        """Test handle queued OpenFlow echo reply messages."""
332
        (mock_send_features_request, mock_settings) = args
333
        mock_settings.return_value = True
334
        mock_event = MagicMock()
335
        self.napp.handle_queued_openflow_echo_reply(mock_event)
336
        mock_send_features_request.assert_called_with(mock_event.destination)
337
338
    @patch('pyof.utils.v0x04.controller2switch.'
339
           'features_request.FeaturesRequest')
340
    @patch('napps.kytos.of_core.main.Main.emit_message_out')
341
    def test_send_features_request(self, *args):
342
        """Test send send_features_request."""
343
        (mock_emit_message_out, mock_features_request) = args
344
        mock_destination = MagicMock()
345
        mock_destination.protocol.version = 4
346
        mock_features_request.return_value = "A"
347
        self.napp.send_features_request(mock_destination)
348
        mock_features_request.assert_called()
349
        mock_emit_message_out.assert_called_with(mock_destination, "A")
350
351
    def test_handle_features_request_sent(self):
352
        """Test tests_handle_features_request_sent."""
353
        mock_protocol = MagicMock()
354
        mock_protocol.protocol.state = 'sending_features'
355
        expected = 'waiting_features_reply'
356
        name = 'kytos/of_core.v0x0[14].messages.out.ofpt_features_request'
357
        content = {'destination': mock_protocol}
358
        mock_event = get_kytos_event_mock(name=name, content=content)
359
        self.napp.handle_features_request_sent(mock_event)
360
        self.assertEqual(mock_event.destination.protocol.state, expected)
361
362
    def test_handle_openflow_in_hello_failed(self):
363
        """Test handle_openflow_in_hello_failed."""
364
        mock_destination = MagicMock()
365
        content = {'destination': mock_destination}
366
        mock_event = get_kytos_event_mock(name='kytos/of_core',
367
                                          content=content)
368
        self.napp.handle_openflow_in_hello_failed(mock_event)
369
        self.assertEqual(mock_event.destination.close.call_count, 1)
370
371
    @patch('kytos.core.buffers.KytosEventBuffer.put')
372
    @patch('napps.kytos.of_core.main.Ethernet')
373
    def test_update_links(self, *args):
374
        """Test update_links."""
375
        (mock_ethernet, mock_buffer_put) = args
376
        ethernet = create_autospec(Ethernet)
377
        ethernet.ether_type = "A"
378
        mock_ethernet.side_effect = ethernet
379
        mock_message = MagicMock()
380
        mock_source = MagicMock()
381
        self.napp.update_links(mock_message, mock_source)
382
        mock_ethernet.assert_called()
383
        mock_buffer_put.assert_called()
384
385
    @patch('kytos.core.buffers.KytosEventBuffer.put')
386
    def test_send_specific_port_mod(self, mock_buffer_put):
387
        """Test send specific port."""
388
        mock_port = MagicMock()
389
        mock_interface = MagicMock()
390
        type(mock_port.state).value = PropertyMock(side_effect=[0, 1, 2])
391
        current_state = 0
392
        self.napp._send_specific_port_mod(mock_port,
393
                                          mock_interface, current_state)
394
        mock_buffer_put.assert_called()
395
396
        current_state = 1
397
        self.napp._send_specific_port_mod(mock_port,
398
                                          mock_interface, current_state)
399
        mock_buffer_put.assert_called()
400
401
        current_state = 2
402
        self.napp._send_specific_port_mod(mock_port,
403
                                          mock_interface, current_state)
404
        mock_buffer_put.assert_called()
405
406
    @patch('kytos.core.buffers.KytosEventBuffer.put')
407
    @patch('napps.kytos.of_core.main.Interface')
408
    @patch('napps.kytos.of_core.main.Main._send_specific_port_mod')
409
    def test_update_port_status(self, *args):
410
        """Test update_port_status."""
411
        (mock_port_mod, mock_interface, mock_buffer_put) = args
412
        mock_port_status = MagicMock()
413
        mock_source = MagicMock()
414
415
        mock_port_status.reason.value.side_effect = [0, 1, 2]
416
        mock_port_status.reason.enum_ref(0).name = 'OFPPR_ADD'
417
        self.napp.update_port_status(mock_port_status, mock_source)
418
        mock_interface.assert_called()
419
420
        # check OFPRR_MODIFY
421
        mock_port_status.reason.enum_ref(1).name = 'OFPPR_MODIFY'
422
        self.napp.update_port_status(mock_port_status, mock_source)
423
        mock_port_mod.assert_called()
424
        mock_buffer_put.assert_called()
425
426
        # check OFPRR_DELETE
427
        mock_port_status.reason.enum_ref(2).name = 'OFPPR_DELETE'
428
        self.napp.update_port_status(mock_port_status, mock_source)
429
        mock_port_mod.assert_called()
430
        mock_buffer_put.assert_called()
431