Passed
Branch master (e02aef)
by Vinicius
06:30
created

build.tests.unit.tracing.test_trace_manager   A

Complexity

Total Complexity 33

Size/Duplication

Total Lines 403
Duplicated Lines 15.88 %

Test Coverage

Coverage 96.75%

Importance

Changes 0
Metric Value
eloc 275
dl 64
loc 403
ccs 238
cts 246
cp 0.9675
rs 9.76
c 0
b 0
f 0
wmc 33

23 Methods

Rating   Name   Duplication   Size   Complexity  
A TestTraceManagerTheadTest.commomn_patches() 0 13 2
A TestTraceManager.test_trace_in_process() 0 7 1
A TestTraceManager.test_avoid_duplicated_request() 0 25 1
A TestTraceManager.teardown_method() 0 3 1
A TestTraceManagerTheadTest.setup_method() 0 6 1
A TestTraceManager.test_is_entry_invalid_not_colored() 0 10 1
A TestTraceManager.test_limit_traces_reached() 0 11 2
A TestTraceManager.test_is_entry_invalid() 0 9 1
A TestTraceManager.test_get_id() 0 10 1
A TestTraceManager.test_duplicated_request() 21 21 1
A TestTraceManager.test_is_entry_valid() 0 14 1
A TestTraceManager.test_new_trace() 22 22 1
A TestTraceManagerTheadTest.test_run_traces() 0 31 2
A TestTraceManagerTheadTest.run_trace_once() 0 7 2
A TestTraceManager.commomn_patches() 0 19 2
A TestTraceManager.test_is_entry_missing_dpid() 0 9 1
A TestTraceManager.test_is_entry_empty_dpid() 0 9 1
A TestTraceManager.test_trace_pending() 0 29 1
A TestTraceManager.create_basic_switches() 21 21 1
A TestTraceManager.setup_method() 0 4 1
A TestTraceManager.test_request_invalid_trace_id() 0 4 1
A TestTraceManager.test_spawn_trace() 0 13 1
B TestTraceManager.test_get_result() 0 55 6

How to fix   Duplicated Code   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

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