Merge "Add 'no timeout' option to wait_for_change"

This commit is contained in:
Zuul 2023-04-19 17:19:23 +00:00 committed by Gerrit Code Review
commit 2b9895b346
2 changed files with 92 additions and 5 deletions

View File

@ -231,17 +231,27 @@ def parse_connection(connection_string):
return [c.strip() for c in connection_string.split(',')]
def wait_for_change(_idl, timeout, seqno=None):
def wait_for_change(_idl, timeout=None, seqno=None):
"""Wait for the Idl seqno to change
:param _idl: The Idl instance
:type _idl: ovs.db.idl.Idl
:param timeout: raise a TimeoutException after if timeout > 0/not None
:type timeout: int (seconds) or None
"""
if timeout and timeout <= 0:
timeout = None
if seqno is None:
seqno = _idl.change_seqno
stop = time.time() + timeout
stop = time.time() + timeout if timeout else None
while _idl.change_seqno == seqno and not _idl.run():
ovs_poller = poller.Poller()
_idl.wait(ovs_poller)
ovs_poller.timer_wait(timeout * 1000)
if timeout:
ovs_poller.timer_wait(timeout * 1000)
ovs_poller.block()
if time.time() > stop:
raise Exception("Timeout") # TODO(twilson) use TimeoutException?
if stop and time.time() >= stop:
raise exceptions.TimeoutException()
def get_column_value(row, col):

View File

@ -12,13 +12,20 @@
# License for the specific language governing permissions and limitations
# under the License.
import unittest
from unittest import mock
import testscenarios
from ovsdbapp import api
from ovsdbapp.backend.ovs_idl import idlutils
from ovsdbapp import exceptions
from ovsdbapp.tests import base
load_tests = testscenarios.load_tests_apply_scenarios
class MockColumn(object):
def __init__(self, name, type, is_optional=False, test_value=None):
self.name = name
@ -191,6 +198,76 @@ class TestIdlUtils(base.TestCase):
self.assertRaises(AssertionError, idlutils.index_name)
class TestWaitForChange(base.TestCase):
assertRaises = unittest.TestCase.assertRaises # context manager support
scenarios = testscenarios.multiply_scenarios([
('seqno matches', dict(seqno_eq=True)),
('seqno unmatched', dict(seqno_eq=False)),
], [
('Idl.run returns False', dict(run_=False)),
('Idl.run returns True', dict(run_=True)),
], [
('timeout is None', dict(timeout=None)),
('timeout is negative', dict(timeout=-1)),
('timeout is zero', dict(timeout=0)),
('timeout is positive', dict(timeout=1)),
], [
('timeout not elapsed', dict(timed_out=False)),
('timeout is elapsed', dict(timed_out=True)),
])
def _make_idl_mock(self):
idl = mock.MagicMock()
idl.change_seqno = 42
idl.run.return_value = self.run_
idl.wait.side_effect = [None, None, StopIteration]
return idl
def test_wait_for_change(self):
timeout = self.timeout and self.timeout > 0
exc_raised = False
if self.seqno_eq and not self.run_:
if not timeout or not self.timed_out:
exc_raised = StopIteration
elif timeout and self.timed_out:
exc_raised = exceptions.TimeoutException
expected = {
'idl_wait': self.seqno_eq and not self.run_,
'timer_wait': self.seqno_eq and not self.run_ and timeout,
'exc_raised': exc_raised}
Idl = self._make_idl_mock()
now = 228399780
if timeout:
end_time = now + self.timeout - int(not self.timed_out)
else:
end_time = Exception
poller_inst = mock.MagicMock()
seqno = Idl.change_seqno if self.seqno_eq else Idl.change_seqno - 1
@mock.patch.object(idlutils.time, 'time', side_effect=[now, end_time])
@mock.patch.object(idlutils.poller, 'Poller', return_value=poller_inst)
def do_test(_poll_mock, _time_mock):
if expected['exc_raised']:
with self.assertRaises(expected['exc_raised']):
idlutils.wait_for_change(Idl, self.timeout, seqno)
else:
idlutils.wait_for_change(Idl, self.timeout, seqno)
if expected['idl_wait']:
Idl.wait.assert_called()
else:
Idl.wait.assert_not_called()
if expected['timer_wait']:
poller_inst.timer_wait.assert_called()
else:
poller_inst.timer_wait.assert_not_called()
do_test()
class TestMergeIntersection(base.TestCase):
def test_no_args(self):
result = idlutils.merge_intersection()