@@ -90,12 +90,26 @@ def setup_teardown_multi_asic():
9090@pytest .fixture (scope = "class" )
9191def setup_teardown_fastpath ():
9292 """
93- Fast path test fixture - directly imports and tests functions to achieve coverage.
93+ Fast path test fixture - does NOT set UTILITIES_UNIT_TESTING=2
94+ so the production fast path (_addr_show) is exercised for coverage.
9495 """
9596 os .environ ["PATH" ] += os .pathsep + scripts_path
96- os .environ ["UTILITIES_UNIT_TESTING" ] = "1"
97+ # Store original values to restore later
98+ original_ut = os .environ .get ("UTILITIES_UNIT_TESTING" )
99+ original_topo = os .environ .get ("UTILITIES_UNIT_TESTING_TOPOLOGY" )
100+
101+ # Don't set UTILITIES_UNIT_TESTING=2 to test the fast production path
102+ # Explicitly unset to ensure we're not in TEST_MODE
103+ os .environ .pop ("UTILITIES_UNIT_TESTING" , None )
104+ os .environ .pop ("UTILITIES_UNIT_TESTING_TOPOLOGY" , None )
105+
97106 yield
98- os .environ ["UTILITIES_UNIT_TESTING" ] = "0"
107+
108+ # Restore original environment
109+ if original_ut is not None :
110+ os .environ ["UTILITIES_UNIT_TESTING" ] = original_ut
111+ if original_topo is not None :
112+ os .environ ["UTILITIES_UNIT_TESTING_TOPOLOGY" ] = original_topo
99113
100114
101115def verify_output (output , expected_output ):
@@ -184,17 +198,53 @@ class TestShowIpIntFastPath(object):
184198
185199 def test_addr_show_ipv4 (self ):
186200 """Test _addr_show with IPv4 addresses - validates fast path is called"""
187- return_code , result = get_result_and_return_code (['ipintutil' ])
188- # Simple check: as long as we get output without error, fast path worked
189- assert return_code == 0
190- assert len (result ) > 0
201+ from importlib .machinery import SourceFileLoader
202+
203+ ipintutil_path = os .path .join (scripts_path , 'ipintutil' )
204+ loader = SourceFileLoader ("ipintutil_v4" , ipintutil_path )
205+ spec = importlib .util .spec_from_loader ("ipintutil_v4" , loader )
206+ ipintutil = importlib .util .module_from_spec (spec )
207+
208+ ip_output = """\
209+ 2: Ethernet0 inet 20.1.1.1/24 scope global Ethernet0
210+ 3: PortChannel0001 inet 30.1.1.1/24 scope global PortChannel0001
211+ """
212+ mock_config_db = mock .MagicMock ()
213+ mock_config_db .get_table .return_value = {}
214+
215+ with mock .patch ('subprocess.check_output' , return_value = ip_output ), \
216+ mock .patch ('swsscommon.swsscommon.ConfigDBConnector' , return_value = mock_config_db ):
217+
218+ loader .exec_module (ipintutil )
219+ result = ipintutil ._addr_show ('' , netifaces .AF_INET , 'all' )
220+ # Should return dict with interfaces
221+ assert isinstance (result , dict )
222+ assert len (result ) >= 0
191223
192224 def test_addr_show_ipv6 (self ):
193225 """Test _addr_show with IPv6 addresses - validates fast path is called"""
194- return_code , result = get_result_and_return_code (['ipintutil' , '-a' , 'ipv6' ])
195- # Simple check: as long as we get output without error, fast path worked
196- assert return_code == 0
197- assert len (result ) > 0
226+ from importlib .machinery import SourceFileLoader
227+
228+ ipintutil_path = os .path .join (scripts_path , 'ipintutil' )
229+ loader = SourceFileLoader ("ipintutil_v6" , ipintutil_path )
230+ spec = importlib .util .spec_from_loader ("ipintutil_v6" , loader )
231+ ipintutil = importlib .util .module_from_spec (spec )
232+
233+ ip_output = """\
234+ 2: Ethernet0 inet6 2100::1/64 scope global
235+ 3: PortChannel0001 inet6 ab00::1/64 scope global
236+ """
237+ mock_config_db = mock .MagicMock ()
238+ mock_config_db .get_table .return_value = {}
239+
240+ with mock .patch ('subprocess.check_output' , return_value = ip_output ), \
241+ mock .patch ('swsscommon.swsscommon.ConfigDBConnector' , return_value = mock_config_db ):
242+
243+ loader .exec_module (ipintutil )
244+ result = ipintutil ._addr_show ('' , netifaces .AF_INET6 , 'all' )
245+ # Should return dict with interfaces
246+ assert isinstance (result , dict )
247+ assert len (result ) >= 0
198248
199249 def test_addr_show_malformed_output (self ):
200250 """Test _addr_show handles malformed ip addr output gracefully"""
@@ -212,7 +262,11 @@ def test_addr_show_malformed_output(self):
2122622: Ethernet0 inet
2132633: Vlan100
214264"""
215- with mock .patch ('subprocess.check_output' , return_value = malformed_output ):
265+ mock_config_db = mock .MagicMock ()
266+ mock_config_db .get_table .return_value = {}
267+
268+ with mock .patch ('subprocess.check_output' , return_value = malformed_output ), \
269+ mock .patch ('swsscommon.swsscommon.ConfigDBConnector' , return_value = mock_config_db ):
216270 loader .exec_module (ipintutil )
217271 result = ipintutil ._addr_show ('' , netifaces .AF_INET , 'all' )
218272 # Should return empty or minimal dict, not crash
@@ -228,7 +282,11 @@ def test_addr_show_subprocess_error(self):
228282 spec = importlib .util .spec_from_loader ("ipintutil_error" , loader )
229283 ipintutil = importlib .util .module_from_spec (spec )
230284
231- with mock .patch ('subprocess.check_output' , side_effect = subprocess .CalledProcessError (1 , 'cmd' )):
285+ mock_config_db = mock .MagicMock ()
286+ mock_config_db .get_table .return_value = {}
287+
288+ with mock .patch ('subprocess.check_output' , side_effect = subprocess .CalledProcessError (1 , 'cmd' )), \
289+ mock .patch ('swsscommon.swsscommon.ConfigDBConnector' , return_value = mock_config_db ):
232290 loader .exec_module (ipintutil )
233291 result = ipintutil ._addr_show ('' , netifaces .AF_INET , 'all' )
234292 # Should return empty dict on error
@@ -245,13 +303,17 @@ def test_addr_show_with_namespace(self):
245303
246304 ip_output = "2: Ethernet0 inet 10.0.0.1/24 scope global Ethernet0\n "
247305
306+ mock_config_db = mock .MagicMock ()
307+ mock_config_db .get_table .return_value = {}
308+
248309 def mock_check_output (cmd , * args , ** kwargs ):
249310 # Verify namespace command is constructed correctly
250311 if 'ip' in cmd and 'netns' in cmd and 'exec' in cmd :
251312 return ip_output
252313 return ip_output
253314
254- with mock .patch ('subprocess.check_output' , side_effect = mock_check_output ):
315+ with mock .patch ('subprocess.check_output' , side_effect = mock_check_output ), \
316+ mock .patch ('swsscommon.swsscommon.ConfigDBConnector' , return_value = mock_config_db ):
255317 loader .exec_module (ipintutil )
256318 result = ipintutil ._addr_show ('asic0' , netifaces .AF_INET , 'all' )
257319 # Should process namespace command and return results
@@ -270,8 +332,12 @@ def test_get_ip_intfs_in_namespace_fast_path(self):
270332 2: Ethernet0 inet 20.1.1.1/24 scope global Ethernet0
2713333: PortChannel0001 inet 30.1.1.1/24 scope global PortChannel0001
272334"""
335+ mock_config_db = mock .MagicMock ()
336+ mock_config_db .get_table .return_value = {}
337+
273338 with mock .patch ('subprocess.check_output' , return_value = ip_output ), \
274339 mock .patch ('subprocess.Popen' ) as mock_popen , \
340+ mock .patch ('swsscommon.swsscommon.ConfigDBConnector' , return_value = mock_config_db ), \
275341 mock .patch ('os.path.exists' , return_value = True ):
276342
277343 mock_proc = mock .MagicMock ()
@@ -283,7 +349,7 @@ def test_get_ip_intfs_in_namespace_fast_path(self):
283349
284350 # Verify we get interface data back
285351 assert isinstance (result , dict )
286- # In fast path with UTILITIES_UNIT_TESTING=1 , should have interfaces
352+ # In fast path, should have interfaces
287353 assert len (result ) >= 0
288354
289355 def test_skip_interface_filtering (self ):
@@ -302,8 +368,12 @@ def test_skip_interface_filtering(self):
3023683: veth123 inet 10.0.0.1/24 scope global veth123
3033694: Ethernet0 inet 20.1.1.1/24 scope global Ethernet0
304370"""
371+ mock_config_db = mock .MagicMock ()
372+ mock_config_db .get_table .return_value = {}
373+
305374 with mock .patch ('subprocess.check_output' , return_value = ip_output ), \
306375 mock .patch ('subprocess.Popen' ) as mock_popen , \
376+ mock .patch ('swsscommon.swsscommon.ConfigDBConnector' , return_value = mock_config_db ), \
307377 mock .patch ('os.path.exists' , return_value = True ):
308378
309379 mock_proc = mock .MagicMock ()
0 commit comments