1717
1818from neutron .common .ovn import constants
1919from neutron .conf .plugins .ml2 .drivers .ovn import ovn_conf
20+ from neutron .plugins .ml2 import db as ml2_db
2021from neutron .plugins .ml2 .drivers .ovn .mech_driver .ovsdb import ovn_client
2122from neutron .tests import base
2223from neutron .tests .unit import fake_resources as fakes
2526from neutron_lib .api .definitions import portbindings
2627from neutron_lib .services .logapi import constants as log_const
2728
29+ from tenacity import wait_none
30+
2831
2932class TestOVNClientBase (base .BaseTestCase ):
3033
@@ -47,6 +50,9 @@ def setUp(self):
4750 fakes .FakeChassis .create (
4851 attrs = {'hostname' : self .fake_smartnic_hostname }))
4952
53+ # Disable tenacity wait for UT
54+ self .ovn_client ._wait_for_port_bindings_host .retry .wait = wait_none ()
55+
5056 def test_vnic_normal_unbound_port (self ):
5157 self .assertEqual (
5258 '' ,
@@ -139,6 +145,45 @@ def test_update_lsp_host_info_up(self):
139145 'Logical_Switch_Port' , port_id ,
140146 ('external_ids' , {constants .OVN_HOST_ID_EXT_ID_KEY : host_id }))
141147
148+ def test_update_lsp_host_info_up_retry (self ):
149+ context = mock .MagicMock ()
150+ host_id = 'fake-binding-host-id'
151+ port_id = 'fake-port-id'
152+ db_port_no_host = mock .Mock (
153+ id = port_id , port_bindings = [mock .Mock (host = "" )])
154+ db_port = mock .Mock (
155+ id = port_id , port_bindings = [mock .Mock (host = host_id )])
156+
157+ with mock .patch .object (
158+ self .ovn_client , '_wait_for_port_bindings_host' ) as mock_wait :
159+ mock_wait .return_value = db_port
160+ self .ovn_client .update_lsp_host_info (context , db_port_no_host )
161+
162+ # Assert _wait_for_port_bindings_host was called
163+ mock_wait .assert_called_once_with (context , port_id )
164+
165+ # Assert host_id was set
166+ self .nb_idl .db_set .assert_called_once_with (
167+ 'Logical_Switch_Port' , port_id ,
168+ ('external_ids' , {constants .OVN_HOST_ID_EXT_ID_KEY : host_id }))
169+
170+ def test_update_lsp_host_info_up_retry_fail (self ):
171+ context = mock .MagicMock ()
172+ port_id = 'fake-port-id'
173+ db_port_no_host = mock .Mock (
174+ id = port_id , port_bindings = [mock .Mock (host = "" )])
175+
176+ with mock .patch .object (
177+ self .ovn_client , '_wait_for_port_bindings_host' ) as mock_wait :
178+ mock_wait .side_effect = RuntimeError ("boom" )
179+ self .ovn_client .update_lsp_host_info (context , db_port_no_host )
180+
181+ # Assert _wait_for_port_bindings_host was called
182+ mock_wait .assert_called_once_with (context , port_id )
183+
184+ # Assert host_id was NOT set
185+ self .assertFalse (self .nb_idl .db_set .called )
186+
142187 def test_update_lsp_host_info_down (self ):
143188 context = mock .MagicMock ()
144189 port_id = 'fake-port-id'
@@ -150,6 +195,47 @@ def test_update_lsp_host_info_down(self):
150195 'Logical_Switch_Port' , port_id , 'external_ids' ,
151196 constants .OVN_HOST_ID_EXT_ID_KEY , if_exists = True )
152197
198+ @mock .patch .object (ml2_db , 'get_port' )
199+ def test__wait_for_port_bindings_host (self , mock_get_port ):
200+ context = mock .MagicMock ()
201+ host_id = 'fake-binding-host-id'
202+ port_id = 'fake-port-id'
203+ db_port_no_host = mock .Mock (
204+ id = port_id , port_bindings = [mock .Mock (host = "" )])
205+ db_port = mock .Mock (
206+ id = port_id , port_bindings = [mock .Mock (host = host_id )])
207+
208+ mock_get_port .side_effect = (db_port_no_host , db_port )
209+
210+ ret = self .ovn_client ._wait_for_port_bindings_host (
211+ context , port_id )
212+
213+ self .assertEqual (ret , db_port )
214+
215+ expected_calls = [mock .call (context , port_id ),
216+ mock .call (context , port_id )]
217+ mock_get_port .assert_has_calls (expected_calls )
218+
219+ @mock .patch .object (ml2_db , 'get_port' )
220+ def test__wait_for_port_bindings_host_fail (self , mock_get_port ):
221+ context = mock .MagicMock ()
222+ port_id = 'fake-port-id'
223+ db_port_no_pb = mock .Mock (id = port_id , port_bindings = [])
224+ db_port_no_host = mock .Mock (
225+ id = port_id , port_bindings = [mock .Mock (host = "" )])
226+
227+ mock_get_port .side_effect = (
228+ db_port_no_pb , db_port_no_host , db_port_no_host )
229+
230+ self .assertRaises (
231+ RuntimeError , self .ovn_client ._wait_for_port_bindings_host ,
232+ context , port_id )
233+
234+ expected_calls = [mock .call (context , port_id ),
235+ mock .call (context , port_id ),
236+ mock .call (context , port_id )]
237+ mock_get_port .assert_has_calls (expected_calls )
238+
153239
154240class TestOVNClientFairMeter (TestOVNClientBase ,
155241 test_log_driver .TestOVNDriverBase ):
0 commit comments