@@ -2575,6 +2575,173 @@ def get_host_lane_assignment_option_side_effect(app):
25752575 appl = common .get_cmis_application_desired (mock_xcvr_api , host_lane_count , speed )
25762576 assert task .get_cmis_host_lanes_mask (mock_xcvr_api , appl , host_lane_count , subport ) == expected
25772577
2578+ @pytest .mark .parametrize ("gearbox_data, expected_dict" , [
2579+ # Test case 1: Gearbox port with 2 line lanes
2580+ ({
2581+ "interface:0" : {
2582+ "name" : "Ethernet0" ,
2583+ "index" : "0" ,
2584+ "phy_id" : "1" ,
2585+ "system_lanes" : "300,301,302,303" ,
2586+ "line_lanes" : "304,305"
2587+ }
2588+ }, {"Ethernet0" : 2 }),
2589+ # Test case 2: Multiple gearbox ports
2590+ ({
2591+ "interface:0" : {
2592+ "name" : "Ethernet0" ,
2593+ "index" : "0" ,
2594+ "phy_id" : "1" ,
2595+ "system_lanes" : "300,301,302,303" ,
2596+ "line_lanes" : "304,305,306,307"
2597+ },
2598+ "interface:200" : {
2599+ "name" : "Ethernet200" ,
2600+ "index" : "200" ,
2601+ "phy_id" : "2" ,
2602+ "system_lanes" : "400,401" ,
2603+ "line_lanes" : "404,405"
2604+ }
2605+ }, {"Ethernet0" : 4 , "Ethernet200" : 2 }),
2606+ # Test case 3: Empty gearbox data
2607+ ({}, {}),
2608+ # Test case 4: Gearbox interface with empty line_lanes
2609+ ({
2610+ "interface:0" : {
2611+ "name" : "Ethernet0" ,
2612+ "index" : "0" ,
2613+ "phy_id" : "1" ,
2614+ "system_lanes" : "300,301,302,303" ,
2615+ "line_lanes" : ""
2616+ }
2617+ }, {}),
2618+ # Test case 5: Non-interface keys (should be ignored)
2619+ ({
2620+ "interface:0" : {
2621+ "name" : "Ethernet0" ,
2622+ "index" : "0" ,
2623+ "phy_id" : "1" ,
2624+ "system_lanes" : "300,301,302,303" ,
2625+ "line_lanes" : "304,305"
2626+ },
2627+ "phy:1" : {
2628+ "name" : "phy1" ,
2629+ "some_field" : "some_value"
2630+ }
2631+ }, {"Ethernet0" : 2 })
2632+ ])
2633+ def test_XcvrTableHelper_get_gearbox_line_lanes_dict (self , gearbox_data , expected_dict ):
2634+ # Mock the XcvrTableHelper and APPL_DB access
2635+ mock_appl_db = MagicMock ()
2636+ mock_gearbox_table = MagicMock ()
2637+
2638+ # Mock table.getKeys() to return gearbox interface keys
2639+ mock_gearbox_table .getKeys .return_value = list (gearbox_data .keys ())
2640+
2641+ # Mock table.get() to return gearbox interface data
2642+ def mock_get_side_effect (key ):
2643+ if key in gearbox_data :
2644+ # Convert dict to list of tuples for fvs format
2645+ interface_data = gearbox_data [key ]
2646+ fvs_list = [(k , v ) for k , v in interface_data .items ()]
2647+ return (True , fvs_list )
2648+ return (False , [])
2649+
2650+ mock_gearbox_table .get .side_effect = mock_get_side_effect
2651+
2652+ # Mock swsscommon.Table constructor to return our mock table
2653+ with patch ('xcvrd.xcvrd_utilities.xcvr_table_helper.swsscommon.Table' , return_value = mock_gearbox_table ):
2654+ # Mock the helper_logger to avoid logging during tests
2655+ with patch ('xcvrd.xcvrd_utilities.xcvr_table_helper.helper_logger' ):
2656+ helper = XcvrTableHelper (DEFAULT_NAMESPACE )
2657+ helper .appl_db = {0 : mock_appl_db } # Mock the appl_db dict
2658+
2659+ result = helper .get_gearbox_line_lanes_dict ()
2660+ assert result == expected_dict
2661+
2662+ @pytest .mark .parametrize ("gearbox_lanes_dict, lport, port_config_lanes, expected_count" , [
2663+ # Test case 1: Gearbox data available, should use gearbox count
2664+ ({"Ethernet0" : 2 }, "Ethernet0" , "25,26,27,28" , 2 ),
2665+ # Test case 2: Gearbox data available with 4 lanes
2666+ ({"Ethernet0" : 4 }, "Ethernet0" , "29,30" , 4 ),
2667+ # Test case 3: No gearbox data for this port, should use port config
2668+ ({"Ethernet4" : 2 }, "Ethernet0" , "33,34,35,36" , 4 ),
2669+ # Test case 4: Empty gearbox dict, should use port config
2670+ ({}, "Ethernet0" , "37,38" , 2 ),
2671+ # Test case 5: Multiple ports in gearbox dict
2672+ ({"Ethernet0" : 2 , "Ethernet4" : 4 }, "Ethernet0" , "25,26,27,28" , 2 ),
2673+ # Test case 6: Port not in gearbox dict
2674+ ({"Ethernet4" : 4 }, "Ethernet8" , "41,42,43" , 3 )
2675+ ])
2676+ def test_CmisManagerTask_get_host_lane_count (self , gearbox_lanes_dict , lport , port_config_lanes , expected_count ):
2677+ port_mapping = PortMapping ()
2678+ stop_event = threading .Event ()
2679+ task = CmisManagerTask (DEFAULT_NAMESPACE , port_mapping , stop_event )
2680+
2681+ result = task .get_host_lane_count (lport , port_config_lanes , gearbox_lanes_dict )
2682+ assert result == expected_count
2683+
2684+ def test_CmisManagerTask_gearbox_integration_end_to_end (self ):
2685+ """Test end-to-end integration of gearbox line lanes with CMIS application selection"""
2686+ port_mapping = PortMapping ()
2687+ stop_event = threading .Event ()
2688+ task = CmisManagerTask (DEFAULT_NAMESPACE , port_mapping , stop_event )
2689+
2690+ # Mock gearbox lanes dictionary - port has 4 system lanes but only 2 line lanes
2691+ gearbox_lanes_dict = {"Ethernet0" : 2 } # 2 line lanes from gearbox
2692+
2693+ # Mock port config - would normally give 4 lanes
2694+ port_config_lanes = "25,26,27,28" # 4 lanes from port config
2695+
2696+ # Mock CMIS API with application advertisement
2697+ mock_xcvr_api = MagicMock ()
2698+ mock_xcvr_api .get_application_advertisement .return_value = {
2699+ 1 : {
2700+ 'host_electrical_interface_id' : '100GAUI-2 C2M (Annex 135G)' ,
2701+ 'module_media_interface_id' : '100G-FR/100GBASE-FR1 (Cl 140)' ,
2702+ 'media_lane_count' : 1 ,
2703+ 'host_lane_count' : 2 , # Matches our gearbox line lanes
2704+ 'host_lane_assignment_options' : 85
2705+ },
2706+ 2 : {
2707+ 'host_electrical_interface_id' : 'CAUI-4 C2M (Annex 83E)' ,
2708+ 'module_media_interface_id' : 'Active Cable assembly' ,
2709+ 'media_lane_count' : 4 ,
2710+ 'host_lane_count' : 4 , # Would match port config lanes
2711+ 'host_lane_assignment_options' : 17
2712+ }
2713+ }
2714+
2715+ # Test the integration: should use gearbox line lanes (2) not port config lanes (4)
2716+ host_lane_count = task .get_host_lane_count ("Ethernet0" , port_config_lanes , gearbox_lanes_dict )
2717+ assert host_lane_count == 2 # Should use gearbox line lanes, not port config
2718+
2719+ # Test that this leads to correct CMIS application selection
2720+ with patch ('xcvrd.xcvrd_utilities.common.is_cmis_api' , return_value = True ):
2721+ appl = common .get_cmis_application_desired (mock_xcvr_api , host_lane_count , 100000 )
2722+ assert appl == 1 # Should select application 1 (2 lanes) not application 2 (4 lanes)
2723+
2724+ def test_CmisManagerTask_gearbox_caching_integration (self ):
2725+ """Test that gearbox lanes dictionary is properly cached and used in task worker"""
2726+ port_mapping = PortMapping ()
2727+ stop_event = threading .Event ()
2728+ task = CmisManagerTask (DEFAULT_NAMESPACE , port_mapping , stop_event )
2729+
2730+ # Mock the XcvrTableHelper to return a gearbox lanes dictionary
2731+ mock_gearbox_lanes_dict = {"Ethernet0" : 2 , "Ethernet4" : 4 }
2732+ task .xcvr_table_helper = MagicMock ()
2733+ task .xcvr_table_helper .get_gearbox_line_lanes_dict .return_value = mock_gearbox_lanes_dict
2734+
2735+ # Test that get_host_lane_count uses the cached dictionary correctly
2736+ result1 = task .get_host_lane_count ("Ethernet0" , "25,26,27,28" , mock_gearbox_lanes_dict )
2737+ assert result1 == 2 # Should use gearbox count
2738+
2739+ result2 = task .get_host_lane_count ("Ethernet4" , "29,30" , mock_gearbox_lanes_dict )
2740+ assert result2 == 4 # Should use gearbox count
2741+
2742+ result3 = task .get_host_lane_count ("Ethernet8" , "33,34,35" , mock_gearbox_lanes_dict )
2743+ assert result3 == 3 # Should fall back to port config count
2744+
25782745 @patch ('swsscommon.swsscommon.FieldValuePairs' )
25792746 def test_CmisManagerTask_post_port_active_apsel_to_db_error_cases (self , mock_field_value_pairs ):
25802747 mock_xcvr_api = MagicMock ()
0 commit comments