Merge pull request #1593 from dbungert/SingleInstanceTask-wait

Single instance task wait
This commit is contained in:
Dan Bungert 2023-03-13 19:59:32 -06:00 committed by GitHub
commit 71a5788c43
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 43 additions and 14 deletions

View File

@ -78,6 +78,7 @@ flake8:
.PHONY: unit
unit: gitdeps
timeout 120 \
$(PYTHON) -m pytest --ignore curtin --ignore probert \
--ignore subiquity/tests/api

View File

@ -384,7 +384,7 @@ class FilesystemController(SubiquityController, FilesystemManipulator):
self.guided_direct(gap)
async def _probe_response(self, wait, resp_cls):
if self._probe_task.task is None or not self._probe_task.task.done():
if not self._probe_task.done():
if wait:
await self._start_task
await self._probe_task.wait()
@ -394,8 +394,7 @@ class FilesystemController(SubiquityController, FilesystemManipulator):
return resp_cls(
status=ProbeStatus.FAILED,
error_report=self._errors[True][1].ref())
if self._get_system_task.task is None or \
not self._get_system_task.task.done():
if not self._get_system_task.done():
if wait:
await self._get_system_task.wait()
else:

View File

@ -14,7 +14,7 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import copy
from unittest import mock, TestCase, IsolatedAsyncioTestCase
from unittest import mock, IsolatedAsyncioTestCase
import uuid
from subiquitycore.tests.parameterized import parameterized
@ -75,7 +75,7 @@ class TestSubiquityControllerFilesystem(IsolatedAsyncioTestCase):
self.assertTrue({'defaults', 'os'} <= actual)
class TestGuided(TestCase):
class TestGuided(IsolatedAsyncioTestCase):
boot_expectations = [
(Bootloader.UEFI, 'gpt', '/boot/efi'),
(Bootloader.UEFI, 'msdos', '/boot/efi'),
@ -96,7 +96,7 @@ class TestGuided(TestCase):
self.d1 = make_disk(self.model, ptable=ptable)
@parameterized.expand(boot_expectations)
def test_guided_direct(self, bootloader, ptable, p1mnt):
async def test_guided_direct(self, bootloader, ptable, p1mnt):
self._guided_setup(bootloader, ptable)
target = GuidedStorageTargetReformat(disk_id=self.d1.id)
self.controller.guided(GuidedChoiceV2(target=target, use_lvm=False))
@ -107,7 +107,7 @@ class TestGuided(TestCase):
self.assertFalse(d1p2.preserve)
self.assertIsNone(gaps.largest_gap(self.d1))
def test_guided_direct_BIOS_MSDOS(self):
async def test_guided_direct_BIOS_MSDOS(self):
self._guided_setup(Bootloader.BIOS, 'msdos')
target = GuidedStorageTargetReformat(disk_id=self.d1.id)
self.controller.guided(GuidedChoiceV2(target=target, use_lvm=False))
@ -117,7 +117,7 @@ class TestGuided(TestCase):
self.assertIsNone(gaps.largest_gap(self.d1))
@parameterized.expand(boot_expectations)
def test_guided_lvm(self, bootloader, ptable, p1mnt):
async def test_guided_lvm(self, bootloader, ptable, p1mnt):
self._guided_setup(bootloader, ptable)
target = GuidedStorageTargetReformat(disk_id=self.d1.id)
self.controller.guided(GuidedChoiceV2(target=target, use_lvm=True))
@ -133,7 +133,7 @@ class TestGuided(TestCase):
self.assertEqual(d1p3, part)
self.assertIsNone(gaps.largest_gap(self.d1))
def test_guided_lvm_BIOS_MSDOS(self):
async def test_guided_lvm_BIOS_MSDOS(self):
self._guided_setup(Bootloader.BIOS, 'msdos')
target = GuidedStorageTargetReformat(disk_id=self.d1.id)
self.controller.guided(GuidedChoiceV2(target=target, use_lvm=True))
@ -178,7 +178,7 @@ class TestGuided(TestCase):
('gpt', None)
)]
)
def test_guided_direct_side_by_side(self, bl, pt, flag):
async def test_guided_direct_side_by_side(self, bl, pt, flag):
self._guided_side_by_side(bl, pt)
parts_before = self.d1._partitions.copy()
gap = gaps.largest_gap(self.d1)
@ -198,7 +198,7 @@ class TestGuided(TestCase):
('gpt', None)
)]
)
def test_guided_lvm_side_by_side(self, bl, pt, flag):
async def test_guided_lvm_side_by_side(self, bl, pt, flag):
self._guided_side_by_side(bl, pt)
parts_before = self.d1._partitions.copy()
gap = gaps.largest_gap(self.d1)
@ -213,18 +213,18 @@ class TestGuided(TestCase):
self.assertEqual(flag, p_data.flag)
class TestLayout(TestCase):
class TestLayout(IsolatedAsyncioTestCase):
def setUp(self):
self.app = make_app()
self.app.opts.bootloader = None
self.fsc = FilesystemController(app=self.app)
@parameterized.expand([('reformat_disk',), ('use_gap',)])
def test_good_modes(self, mode):
async def test_good_modes(self, mode):
self.fsc.validate_layout_mode(mode)
@parameterized.expand([('resize_biggest',), ('use_free',)])
def test_bad_modes(self, mode):
async def test_bad_modes(self, mode):
with self.assertRaises(ValueError):
self.fsc.validate_layout_mode(mode)

View File

@ -73,6 +73,7 @@ class SingleInstanceTask:
def __init__(self, func, propagate_errors=True, cancel_restart=True):
self.func = func
self.propagate_errors = propagate_errors
self.task_created = asyncio.Event()
self.task = None
# if True, allow subsequent start calls to cancel a running task
# raises TaskAlreadyRunningError if we skip starting the task.
@ -102,11 +103,18 @@ class SingleInstanceTask:
self.task = asyncio.Task(coro)
else:
self.task = coro
self.task_created.set()
return schedule_task(self._start(old))
async def wait(self):
await self.task_created.wait()
while True:
try:
return await self.task
except asyncio.CancelledError:
pass
def done(self):
if self.task is None:
return False
return self.task.done()

View File

@ -45,3 +45,24 @@ class TestSingleInstanceTask(unittest.IsolatedAsyncioTestCase):
sit.task.cancel()
self.assertEqual(expected_call_count, mock_fn.call_count)
self.assertEqual(cancel_restart, restarted)
# previously, wait() may or may not have been safe to call, depending
# on if the task had actually been created yet.
class TestSITWait(unittest.IsolatedAsyncioTestCase):
async def test_wait_started(self):
async def fn():
pass
sit = SingleInstanceTask(fn)
await sit.start()
await asyncio.wait_for(sit.wait(), timeout=1.0)
self.assertTrue(sit.done())
async def test_wait_not_started(self):
async def fn():
self.fail('not supposed to be called')
sit = SingleInstanceTask(fn)
self.assertFalse(sit.done())
with self.assertRaises(asyncio.TimeoutError):
await asyncio.wait_for(sit.wait(), timeout=0.1)
self.assertFalse(sit.done())