build.tests.unit.tracing.test_trace_manager   A
last analyzed

Complexity

Total Complexity 33

Size/Duplication

Total Lines 404
Duplicated Lines 15.84 %

Test Coverage

Coverage 96.75%

Importance

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