Test Failed
Pull Request — master (#20)
by Rogerio
03:59
created

TestTraceManager.test_get_result()   B

Complexity

Conditions 6

Size

Total Lines 57
Code Lines 47

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 6
eloc 47
nop 4
dl 0
loc 57
rs 7.8012
c 0
b 0
f 0

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
"""
2
    Test tracing.trace_manager
3
"""
4
import time
5
from unittest import TestCase
6
from unittest.mock import patch, MagicMock
7
8
from napps.amlight.sdntrace import settings
9
from napps.amlight.sdntrace.tracing.trace_manager import TraceManager
10
from napps.amlight.sdntrace.tracing.trace_entries import TraceEntries
11
from napps.amlight.sdntrace.shared.switches import Switches
12
13
from kytos.lib.helpers import (
14
    get_interface_mock,
15
    get_link_mock,
16
    get_switch_mock,
17
    get_controller_mock,
18
)
19
20
21
# pylint: disable=protected-access
22
class TestTraceManager(TestCase):
23
    """Unit tests for tracing.trace_manager.TraceManager"""
24
25
    def setUp(self):
26
        self.create_basic_switches(get_controller_mock())
27
28
        # The decorator run_on_thread is patched, so methods that listen
29
        # for events do not run on threads while tested.
30
        # Decorators have to be patched before the methods that are
31
        # decorated with them are imported.
32
        patch("kytos.core.helpers.run_on_thread", lambda x: x).start()
33
34
        self.addCleanup(patch.stopall)
35
        self.trace_manager = TraceManager(controller=get_controller_mock())
36
37
    def tearDown(self) -> None:
38
        self.trace_manager.stop_traces()
39
        return super().tearDown()
40
41 View Code Duplication
    @classmethod
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
42
    def create_basic_switches(cls, controller):
43
        """Create basic mock switches for Kytos controller."""
44
        dpid_a = "00:00:00:00:00:00:00:01"
45
        dpid_b = "00:00:00:00:00:00:00:02"
46
47
        mock_switch_a = get_switch_mock(dpid_a, 0x04)
48
        mock_switch_b = get_switch_mock(dpid_b, 0x04)
49
        mock_interface_a = get_interface_mock("s1-eth1", 1, mock_switch_a)
50
        mock_interface_b = get_interface_mock("s2-eth1", 1, mock_switch_b)
51
52
        mock_link = get_link_mock(mock_interface_a, mock_interface_b)
53
        mock_link.id = "cf0f4071be4"
54
        mock_switch_a.id = dpid_a
55
        mock_switch_a.as_dict.return_value = {"metadata": {}}
56
        mock_switch_b.id = dpid_b
57
        mock_switch_b.as_dict.return_value = {"metadata": {}}
58
59
        controller.switches = {dpid_a: mock_switch_a, dpid_b: mock_switch_b}
60
61
        Switches().set_switches(controller.switches)
62
63
    def test_is_entry_invalid(self):
64
        """Test if the entry request does not have a valid switch."""
65
        eth = {"dl_vlan": 100}
66
        dpid = {"dpid": "a", "in_port": 1}
67
        switch = {"switch": dpid, "eth": eth}
68
        entries = {"trace": switch}
69
        entry = self.trace_manager.is_entry_valid(entries)
70
71
        self.assertEqual(entry, "Unknown Switch")
72
73
    def test_is_entry_empty_dpid(self):
74
        """Test if the entry request does not have a valid switch."""
75
        eth = {"dl_vlan": 100}
76
        dpid = {"dpid": "", "in_port": 1}
77
        switch = {"switch": dpid, "eth": eth}
78
        entries = {"trace": switch}
79
        entry = self.trace_manager.is_entry_valid(entries)
80
81
        self.assertEqual(
82
            entry, "Error: dpid allows [a-f], int, and :. Lengths: 1-16 and 23"
83
        )
84
85
    def test_is_entry_missing_dpid(self):
86
        """Test if the entry request with missing dpid."""
87
        eth = {"dl_vlan": 100}
88
        dpid = {}
89
        switch = {"switch": dpid, "eth": eth}
90
        entries = {"trace": switch}
91
        entry = self.trace_manager.is_entry_valid(entries)
92
93
        self.assertEqual(entry, "Error: dpid not provided")
94
95
    def test_is_entry_invalid_not_colored(self):
96
        """Test if the entry request does not have a valid color."""
97
        eth = {"dl_vlan": 100}
98
        dpid = {"dpid": "00:00:00:00:00:00:00:01", "in_port": 1}
99
        switch = {"switch": dpid, "eth": eth}
100
        entries = {"trace": switch}
101
        entry = self.trace_manager.is_entry_valid(entries)
102
        self.assertEqual(entry, "Switch not Colored")
103
104
    @patch("napps.amlight.sdntrace.shared.colors.Colors.get_switch_color")
105
    def test_is_entry_valid(self, mock_colors):
106
        """Test if the entry request is valid."""
107
        mock_colors.return_value = "ee:ee:ee:ee:ee:01"
108
109
        eth = {"dl_vlan": 100}
110
        dpid = {"dpid": "00:00:00:00:00:00:00:01", "in_port": 1}
111
        switch = {"switch": dpid, "eth": eth}
112
        entries = {"trace": switch}
113
        entry = self.trace_manager.is_entry_valid(entries)
114
        self.assertEqual(entry.dpid, "00:00:00:00:00:00:00:01")
115
116 View Code Duplication
    @patch("napps.amlight.sdntrace.shared.colors.Colors.get_switch_color")
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
117
    def test_new_trace(self, mock_colors):
118
        """Test trace manager new trace creation."""
119
        mock_colors.return_value = "ee:ee:ee:ee:ee:01"
120
121
        eth = {"dl_vlan": 100}
122
        dpid = {"dpid": "00:00:00:00:00:00:00:01", "in_port": 1}
123
        switch = {"switch": dpid, "eth": eth}
124
        entries = {"trace": switch}
125
126
        trace_entries = self.trace_manager.is_entry_valid(entries)
127
        self.assertIsInstance(trace_entries, TraceEntries)
128
129
        trace_id = self.trace_manager.new_trace(trace_entries)
130
        self.assertEqual(trace_id, 30001)
131
132
        # new_trace does not check duplicated request.
133
        trace_id = self.trace_manager.new_trace(trace_entries)
134
        self.assertEqual(trace_id, 30002)
135
136
    def test_get_id(self):
137
        """Test trace manager ID control."""
138
        trace_id = self.trace_manager.get_id()
139
        self.assertEqual(trace_id, 30001)
140
141
        trace_id = self.trace_manager.get_id()
142
        self.assertEqual(trace_id, 30002)
143
144
        trace_id = self.trace_manager.get_id()
145
        self.assertEqual(trace_id, 30003)
146
147 View Code Duplication
    @patch("napps.amlight.sdntrace.shared.colors.Colors.get_switch_color")
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
148
    @patch("napps.amlight.sdntrace.tracing.tracer.TracePath.send_trace_probe")
149
    def test_trace_pending(self, mock_send_probe, mock_colors):
150
        """Test trace manager tracing request."""
151
        mock_colors.return_value = "ee:ee:ee:ee:ee:01"
152
        mock_send_probe.return_value = {
153
            "dpid": "00:00:00:00:00:00:00:01",
154
            "port": 1,
155
        }, ""
156
157
        eth = {"dl_vlan": 100}
158
        dpid = {"dpid": "00:00:00:00:00:00:00:01", "in_port": 1}
159
        switch = {"switch": dpid, "eth": eth}
160
        entries = {"trace": switch}
161
162
        trace_entries = self.trace_manager.is_entry_valid(entries)
163
        self.assertIsInstance(trace_entries, TraceEntries)
164
165
        trace_id = self.trace_manager.new_trace(trace_entries)
166
        self.assertEqual(trace_id, 30001)
167
168
        pending = self.trace_manager.number_pending_requests()
169
        self.assertEqual(pending, 1)
170
171
        result = self.trace_manager.get_result(trace_id)
172
        self.assertEqual(result, {"msg": "trace pending"})
173
174
    def test_request_invalid_trace_id(self):
175
        """Test trace manager tracing request."""
176
        result = self.trace_manager.get_result("1234")
177
        self.assertEqual(result, {"msg": "unknown trace id"})
178
179 View Code Duplication
    @patch("napps.amlight.sdntrace.shared.colors.Colors.get_switch_color")
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
180
    @patch("napps.amlight.sdntrace.tracing.tracer.TracePath.send_trace_probe")
181
    def test_trace_in_process(self, mock_send_probe, mock_colors):
182
        """Test trace manager tracing request and processing."""
183
        mock_colors.return_value = "ee:ee:ee:ee:ee:01"
184
        mock_send_probe.return_value = {
185
            "dpid": "00:00:00:00:00:00:00:01",
186
            "port": 1,
187
        }, ""
188
189
        eth = {"dl_vlan": 100}
190
        dpid = {"dpid": "00:00:00:00:00:00:00:01", "in_port": 1}
191
        switch = {"switch": dpid, "eth": eth}
192
        entries = {"trace": switch}
193
194
        trace_entries = self.trace_manager.is_entry_valid(entries)
195
        self.assertIsInstance(trace_entries, TraceEntries)
196
197
        trace_id = self.trace_manager.new_trace(trace_entries)
198
        self.assertEqual(trace_id, 30001)
199
200
        pending = self.trace_manager.number_pending_requests()
201
        self.assertEqual(pending, 1)
202
203
        while pending == 1:
204
            result = self.trace_manager.get_result(trace_id)
205
            pending = self.trace_manager.number_pending_requests()
206
            time.sleep(0.1)
207
208
        self.assertEqual(result, {"msg": "trace in process"})
0 ignored issues
show
introduced by
The variable result does not seem to be defined in case the while loop on line 203 is not entered. Are you sure this can never be the case?
Loading history...
209
210
    @patch("napps.amlight.sdntrace.shared.colors.Colors.get_switch_color")
211
    @patch("napps.amlight.sdntrace.tracing.tracer.TracePath.send_trace_probe")
212
    @patch("napps.amlight.sdntrace.tracing.tracer.TracePath.tracepath_loop")
213
    def test_get_result(self, mock_trace_loop, mock_send_probe, mock_colors):
214
        """Test tracemanager tracing request and resultS."""
215
        mock_colors.return_value = "ee:ee:ee:ee:ee:01"
216
        mock_send_probe.return_value = {
217
            "dpid": "00:00:00:00:00:00:00:01",
218
            "port": 1,
219
        }, ""
220
        mock_trace_loop.return_value = True
221
222
        eth = {"dl_vlan": 100}
223
        dpid = {"dpid": "00:00:00:00:00:00:00:01", "in_port": 1}
224
        switch = {"switch": dpid, "eth": eth}
225
        entries = {"trace": switch}
226
227
        trace_entries = self.trace_manager.is_entry_valid(entries)
228
        trace_id = self.trace_manager.new_trace(trace_entries)
229
        pending = self.trace_manager.number_pending_requests()
230
231
        # Waiting thread to start processing the request
232
        count = 0
233
        while pending == 1:
234
            result = self.trace_manager.get_result(trace_id)
235
            pending = self.trace_manager.number_pending_requests()
236
            time.sleep(0.1)
237
            count += 1
238
            if count > 30:
239
                self.fail("Timeout waiting to start processing trace")
240
                break
241
242
        count = 0
243
        result = self.trace_manager.get_result(trace_id)
244
        # Waiting thread to process the request
245
        while "msg" in result and result["msg"] == "trace in process":
246
            result = self.trace_manager.get_result(trace_id)
247
            time.sleep(0.1)
248
            count += 1
249
            if count > 30:
250
                self.fail("Timeout waiting to process trace")
251
                break
252
253
        self.assertEqual(result["request_id"], 30001)
254
        self.assertEqual(result["result"][0]["type"], "starting")
255
        self.assertEqual(
256
            result["result"][0]["dpid"], "00:00:00:00:00:00:00:01"
257
        )
258
        self.assertEqual(result["result"][0]["port"], 1)
259
        self.assertIsNotNone(result["result"][0]["time"])
260
        self.assertIsNotNone(result["start_time"])
261
        self.assertIsNotNone(result["total_time"])
262
        self.assertEqual(
263
            result["request"]["trace"]["switch"]["dpid"],
264
            "00:00:00:00:00:00:00:01",
265
        )
266
        self.assertEqual(result["request"]["trace"]["switch"]["in_port"], 1)
267
268 View Code Duplication
    @patch("napps.amlight.sdntrace.shared.colors.Colors.get_switch_color")
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
269
    def test_duplicated_request(self, mock_colors):
270
        """Test trace manager new trace creation."""
271
        mock_colors.return_value = "ee:ee:ee:ee:ee:01"
272
273
        eth = {"dl_vlan": 100}
274
        dpid = {"dpid": "00:00:00:00:00:00:00:01", "in_port": 1}
275
        switch = {"switch": dpid, "eth": eth}
276
        entries = {"trace": switch}
277
278
        trace_entries = self.trace_manager.is_entry_valid(entries)
279
        self.assertIsInstance(trace_entries, TraceEntries)
280
281
        trace_id = self.trace_manager.new_trace(trace_entries)
282
        self.assertEqual(trace_id, 30001)
283
284
        duplicated = self.trace_manager.avoid_duplicated_request(trace_entries)
285
        self.assertEqual(duplicated, True)
286
287
    @patch("napps.amlight.sdntrace.shared.colors.Colors.get_switch_color")
288
    def test_avoid_duplicated_request(self, mock_colors):
289
        """Test trace manager new trace creation."""
290
        mock_colors.return_value = "ee:ee:ee:ee:ee:01"
291
292
        eth = {"dl_vlan": 100}
293
        dpid = {"dpid": "00:00:00:00:00:00:00:01", "in_port": 1}
294
        switch = {"switch": dpid, "eth": eth}
295
        entries = {"trace": switch}
296
297
        trace_entries = self.trace_manager.is_entry_valid(entries)
298
        self.assertIsInstance(trace_entries, TraceEntries)
299
300
        trace_id = self.trace_manager.new_trace(trace_entries)
301
        self.assertEqual(trace_id, 30001)
302
303
        entries["trace"]["switch"]["dpid"] = "00:00:00:00:00:00:00:02"
304
        trace_entries = self.trace_manager.is_entry_valid(entries)
305
        self.assertIsInstance(trace_entries, TraceEntries)
306
307
        duplicated = self.trace_manager.avoid_duplicated_request(trace_entries)
308
        self.assertEqual(duplicated, False)
309
310
    def test_limit_traces_reached(self):
311
        """Test trace manager limit for thread processing."""
312
        # filling the running traces array
313
        for i in range(settings.PARALLEL_TRACES - 1):
314
            self.trace_manager._running_traces[i] = i
315
            is_limit = self.trace_manager.limit_traces_reached()
316
            self.assertFalse(is_limit)
317
318
        self.trace_manager._running_traces[settings.PARALLEL_TRACES] = 9999
319
        is_limit = self.trace_manager.limit_traces_reached()
320
        self.assertTrue(is_limit)
321
322
    @patch("napps.amlight.sdntrace.tracing.tracer.TracePath.tracepath")
323
    def test_spawn_trace(self, mock_tracepath):
324
        """Test spawn trace."""
325
        # mock_tracepath
326
        trace_id = 0
327
        trace_entries = MagicMock()
328
329
        self.trace_manager._running_traces[0] = 9999
330
331
        self.trace_manager._spawn_trace(trace_id, trace_entries)
332
333
        mock_tracepath.assert_called_once()
334
        self.assertEqual(len(self.trace_manager._running_traces), 0)
335
336
337
class TestTraceManagerTheadTest(TestCase):
338
    """Now, load all entries at once"""
339
340
    def setUp(self):
341
342
        # The decorator run_on_thread is patched, so methods that listen
343
        # for events do not run on threads while tested.
344
        # Decorators have to be patched before the methods that are
345
        # decorated with them are imported.
346
        patch("kytos.core.helpers.run_on_thread", lambda x: x).start()
347
        # pylint: disable=import-outside-toplevel
348
        self.addCleanup(patch.stopall)
349
350
        self.trace_manager = TraceManager(controller=get_controller_mock())
351
        self.trace_manager.stop_traces()
352
353
        self.count_running_traces = 0
354
355
    def run_trace_once(self):
356
        """function to replace the <flag> in "while <flag>()" code
357
        to run the loop just once."""
358
        if self.count_running_traces == 0:
359
            self.count_running_traces = self.count_running_traces + 1
360
            return True
361
        return False
362
363
    @patch("napps.amlight.sdntrace.shared.colors.Colors.get_switch_color")
364
    @patch("napps.amlight.sdntrace.tracing.tracer.TracePath.send_trace_probe")
365
    @patch("napps.amlight.sdntrace.tracing.tracer.TracePath.tracepath_loop")
366
    def test_run_traces(self, mock_trace_loop, mock_send_probe, mock_colors):
367
        """Test tracemanager tracing request and resultS."""
368
        mock_colors.return_value = "ee:ee:ee:ee:ee:01"
369
        mock_send_probe.return_value = {
370
            "dpid": "00:00:00:00:00:00:00:01",
371
            "port": 1,
372
        }, ""
373
        mock_trace_loop.return_value = True
374
375
        eth = {"dl_vlan": 100}
376
        dpid = {"dpid": "00:00:00:00:00:00:00:01", "in_port": 1}
377
        switch = {"switch": dpid, "eth": eth}
378
        entries = {"trace": switch}
379
380
        trace_entries = self.trace_manager.is_entry_valid(entries)
381
382
        self.trace_manager._request_queue[1] = trace_entries
383
384
        with patch.object(
385
            TraceManager, "is_tracing_running", side_effect=self.run_trace_once
386
        ):
387
            self.trace_manager._run_traces(0.5)
388
389
        self.assertEqual(len(self.trace_manager._request_queue), 0)
390
        self.assertEqual(self.trace_manager.number_pending_requests(), 0)
391