Skip to content

Commit

Permalink
[y_cable] refactor y_cable to a seperate logic and new daemon from xc…
Browse files Browse the repository at this point in the history
…vrd (#219)

* [xcvrd] suuport for integrating y cable within xcvrd

This PR separates the logic of Y-Cable from xcvrd. Before this change we were utilizing xcvrd daemon to control all aspects of Y-Cable right from initialization to processing requests from other entities like orch,linkmgr.
Now we would have another daemon ycabled which will serve this purpose.
Logically everything still remains the same from the perspective of other daemons.
it also take care aspects like init/delete daemon from Y-Cable perspective.

dependent-startup                EXITED    Jan 18 05:40 AM

xcvrd                            RUNNING   pid 33, uptime 20:02:58
ycabled                          RUNNING   pid 218, uptime 0:22:12
Motivation and Context
Required for separating the logic of Y-Cable from xcvrd. This is to ensure that the daemon always works and responds to linkmgr to address its requests

How Has This Been Tested?
Built an image with the changes and ran dualtor specific tests on the change on a 7050cx3 testbed.
Signed-off-by: vaibhav-dahiya <vdahiya@microsoft.com>
  • Loading branch information
vdahiya12 authored Jan 20, 2022
1 parent c4127c2 commit 94fa239
Show file tree
Hide file tree
Showing 15 changed files with 4,852 additions and 2,225 deletions.
3 changes: 3 additions & 0 deletions azure-pipelines.yml
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,9 @@ parameters:
root_dir: sonic-xcvrd
python2: true
python3: true
- name: ycabled
root_dir: sonic-ycabled
python3: true
- name: artifactBranch
type: string
default: 'refs/heads/master'
Expand Down
32 changes: 15 additions & 17 deletions sonic-xcvrd/tests/test_xcvrd.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
from xcvrd.xcvrd_utilities.port_mapping import *
from xcvrd.xcvrd_utilities.sfp_status_helper import *
from xcvrd.xcvrd_utilities.y_cable_helper import *
from xcvrd.xcvrd import *
import copy
import os
Expand All @@ -23,6 +22,7 @@
swsscommon.ProducerStateTable = MagicMock()
swsscommon.SubscriberStateTable = MagicMock()
swsscommon.SonicDBConfig = MagicMock()
#swsscommon.Select = MagicMock()

test_path = os.path.dirname(os.path.abspath(__file__))
modules_path = os.path.dirname(test_path)
Expand All @@ -39,8 +39,6 @@
media_settings_with_comma_dict['GLOBAL_MEDIA_SETTINGS']['1-5,6,7-20,21-32'] = global_media_settings

class TestXcvrdScript(object):
def test_xcvrd_helper_class_run(self):
Y_cable_task = YCableTableUpdateTask(None)

@patch('xcvrd.xcvrd._wrapper_get_sfp_type')
@patch('xcvrd.xcvrd_utilities.port_mapping.PortMapping.logical_port_name_to_physical_port_list', MagicMock(return_value=[0]))
Expand Down Expand Up @@ -569,7 +567,7 @@ def test_DomInfoUpdateTask_handle_port_change_event(self):
def test_DomInfoUpdateTask_task_run_stop(self):
port_mapping = PortMapping()
task = DomInfoUpdateTask(port_mapping)
task.task_run([False])
task.task_run()
task.task_stop()
assert not task.task_thread.is_alive()

Expand All @@ -591,7 +589,7 @@ def test_DomInfoUpdateTask_task_worker(self, mock_select, mock_sub_table, mock_p
task = DomInfoUpdateTask(port_mapping)
task.task_stopping_event.wait = MagicMock(side_effect=[False, True])
mock_detect_error.return_value = True
task.task_worker([False])
task.task_worker()
assert task.port_mapping.logical_port_list.count('Ethernet0')
assert task.port_mapping.get_asic_id_for_logical_port('Ethernet0') == 0
assert task.port_mapping.get_physical_to_logical(1) == ['Ethernet0']
Expand All @@ -600,7 +598,7 @@ def test_DomInfoUpdateTask_task_worker(self, mock_select, mock_sub_table, mock_p
assert mock_post_dom_info.call_count == 0
mock_detect_error.return_value = False
task.task_stopping_event.wait = MagicMock(side_effect=[False, True])
task.task_worker([False])
task.task_worker()
assert mock_post_dom_th.call_count == 1
assert mock_post_dom_info.call_count == 1

Expand All @@ -619,7 +617,7 @@ def test_SfpStateUpdateTask_handle_port_change_event(self, mock_table_helper):
port_change_event = PortChangeEvent('Ethernet0', 1, 0, PortChangeEvent.PORT_ADD)
wait_time = 5
while wait_time > 0:
task.on_port_config_change(stopping_event, [False], port_change_event)
task.on_port_config_change(port_change_event)
if task.port_mapping.logical_port_list:
break
wait_time -= 1
Expand All @@ -632,7 +630,7 @@ def test_SfpStateUpdateTask_handle_port_change_event(self, mock_table_helper):
port_change_event = PortChangeEvent('Ethernet0', 1, 0, PortChangeEvent.PORT_REMOVE)
wait_time = 5
while wait_time > 0:
task.on_port_config_change(stopping_event, [False], port_change_event)
task.on_port_config_change(port_change_event)
if not task.port_mapping.logical_port_list:
break
wait_time -= 1
Expand All @@ -647,7 +645,7 @@ def test_SfpStateUpdateTask_task_run_stop(self):
retry_eeprom_set = set()
task = SfpStateUpdateTask(port_mapping, retry_eeprom_set)
sfp_error_event = multiprocessing.Event()
task.task_run(sfp_error_event, [False])
task.task_run(sfp_error_event)
assert wait_until(5, 1, task.task_process.is_alive)
task.task_stop()
assert wait_until(5, 1, lambda: task.task_process.is_alive() is False)
Expand Down Expand Up @@ -718,23 +716,23 @@ def test_SfpStateUpdateTask_task_worker(self, mock_updata_status, mock_post_sfp_
mock_mapping_event.return_value = SYSTEM_NOT_READY

# Test state machine: STATE_INIT + SYSTEM_NOT_READY event => STATE_INIT + SYSTEM_NOT_READY event ... => STATE_EXIT
task.task_worker(stop_event, sfp_error_event, [False])
task.task_worker(stop_event, sfp_error_event)
assert mock_os_kill.call_count == 1
assert sfp_error_event.is_set()

mock_mapping_event.return_value = SYSTEM_FAIL
mock_os_kill.reset_mock()
sfp_error_event.clear()
# Test state machine: STATE_INIT + SYSTEM_FAIL event => STATE_INIT + SYSTEM_FAIL event ... => STATE_EXIT
task.task_worker(stop_event, sfp_error_event, [False])
task.task_worker(stop_event, sfp_error_event)
assert mock_os_kill.call_count == 1
assert sfp_error_event.is_set()

mock_mapping_event.side_effect = [SYSTEM_BECOME_READY, SYSTEM_NOT_READY]
mock_os_kill.reset_mock()
sfp_error_event.clear()
# Test state machine: STATE_INIT + SYSTEM_BECOME_READY event => STATE_NORMAL + SYSTEM_NOT_READY event ... => STATE_EXIT
task.task_worker(stop_event, sfp_error_event, [False])
task.task_worker(stop_event, sfp_error_event)
assert mock_os_kill.call_count == 1
assert not sfp_error_event.is_set()

Expand All @@ -744,7 +742,7 @@ def test_SfpStateUpdateTask_task_worker(self, mock_updata_status, mock_post_sfp_
sfp_error_event.clear()
# Test state machine: STATE_INIT + SYSTEM_BECOME_READY event => STATE_NORMAL + SYSTEM_FAIL event ... => STATE_INIT
# + SYSTEM_FAIL event ... => STATE_EXIT
task.task_worker(stop_event, sfp_error_event, [False])
task.task_worker(stop_event, sfp_error_event)
assert mock_os_kill.call_count == 1
assert sfp_error_event.is_set()

Expand All @@ -755,7 +753,7 @@ def test_SfpStateUpdateTask_task_worker(self, mock_updata_status, mock_post_sfp_
mock_post_sfp_info.return_value = SFP_EEPROM_NOT_READY
stop_event.is_set = MagicMock(side_effect=[False, True])
# Test state machine: handle SFP insert event, but EEPROM read failure
task.task_worker(stop_event, sfp_error_event, [False])
task.task_worker(stop_event, sfp_error_event)
assert mock_updata_status.call_count == 1
assert mock_post_sfp_info.call_count == 2 # first call and retry call
assert mock_post_dom_info.call_count == 0
Expand All @@ -769,7 +767,7 @@ def test_SfpStateUpdateTask_task_worker(self, mock_updata_status, mock_post_sfp_
mock_updata_status.reset_mock()
mock_post_sfp_info.reset_mock()
# Test state machine: handle SFP insert event, and EEPROM read success
task.task_worker(stop_event, sfp_error_event, [False])
task.task_worker(stop_event, sfp_error_event)
assert mock_updata_status.call_count == 1
assert mock_post_sfp_info.call_count == 1
assert mock_post_dom_info.call_count == 1
Expand All @@ -780,7 +778,7 @@ def test_SfpStateUpdateTask_task_worker(self, mock_updata_status, mock_post_sfp_
mock_change_event.return_value = (True, {1: SFP_STATUS_REMOVED}, {})
mock_updata_status.reset_mock()
# Test state machine: handle SFP remove event
task.task_worker(stop_event, sfp_error_event, [False])
task.task_worker(stop_event, sfp_error_event)
assert mock_updata_status.call_count == 1
assert mock_del_dom.call_count == 1

Expand All @@ -790,7 +788,7 @@ def test_SfpStateUpdateTask_task_worker(self, mock_updata_status, mock_post_sfp_
mock_updata_status.reset_mock()
mock_del_dom.reset_mock()
# Test state machine: handle SFP error event
task.task_worker(stop_event, sfp_error_event, [False])
task.task_worker(stop_event, sfp_error_event)
assert mock_updata_status.call_count == 1
assert mock_del_dom.call_count == 1

Expand Down
Loading

0 comments on commit 94fa239

Please sign in to comment.