diff --git a/tests/foreman/api/test_capsulecontent.py b/tests/foreman/api/test_capsulecontent.py index 806dc18c70c..465c9e55097 100644 --- a/tests/foreman/api/test_capsulecontent.py +++ b/tests/foreman/api/test_capsulecontent.py @@ -53,14 +53,21 @@ from robottelo.utils.issue_handlers import is_open -def _capsule_sync_wait_assert(sat, capsule, start_time=None, timeout=600): - """Query sync status of a given capsule after invoking capsule sync, find some expected sync task(s). - * The capsule's `last_sync_task` is the final task from active_tasks (by highest :id). - * After polling sync task(s), capsule's `last_sync_time` is on or after timestamp. - * No remaining active or failed task(s), after polling the found active task(s). - param start_time; datetime.datetime: time to check final sync was on or after +def _capsule_sync_wait_assert(sat, capsule, start_time=None, timeout=120): + """Query sync status of a given capsule after invoking capsule sync, + find some ongoing sync task(s), or a newer last_sync_time for the capsule. + + * After polling any active_tasks, capsule's `last_sync_time` is on or after timestamp. + * The capsule's `last_sync_task` is the final task from any active_tasks. + * No remaining active or failed task(s) from updated capsule's sync status. + + :param start_time; datetime.datetime: time to check final sync was on or after + :return list: [boolean, dict] + True/False: if an active capsule sync task was found by this method + sync_status: dict of updated response from `nailgun_capsule.content_get_sync()` """ - # get most recent status first, to avoid missing any async task(s) + active_sync = False + # get most recent status first, to avoid missing any quicker async task(s) sync_status = capsule.nailgun_capsule.content_get_sync(synchronous=True, timeout=timeout) active_tasks = sync_status['active_sync_tasks'] @@ -70,21 +77,41 @@ def _capsule_sync_wait_assert(sat, capsule, start_time=None, timeout=600): start_time = ( (start_time - timedelta(seconds=1)).replace(microsecond=0).strftime('%Y-%m-%d %H:%M:%S UTC') ) - # we expect some ongoing sync task(s) - assert len(active_tasks) > 0 - for task in active_tasks: - sat.api.ForemanTask(id=task['id']).poll(timeout=timeout) + if len(active_tasks) > 0: + active_sync = True + # we expect some ongoing sync(s), polled task(s) must succeed + for task in active_tasks: + sat.api.ForemanTask(id=task['id']).poll(timeout=timeout) - # check newest status after polling finished task(s) + # check newest status after polling any found task(s) sync_status = capsule.nailgun_capsule.content_get_sync(synchronous=True, timeout=timeout) - # final active_task was the last sync task - assert active_tasks[-1]['id'] == sync_status['last_sync_task']['id'] + # After polling active task(s), or with no sync tasks found; + # an invoked sync may have just finished before first check of sync_status. + # latest sync time should be newer than start time for both cases. + assert parse(sync_status['last_sync_time']) >= parse(start_time), ( + f' No active sync task(s) found for capsule: {capsule.hostname}.' + f' Capsule last_sync_time: {sync_status["last_sync_time"]}, was not newer than start_time: {start_time}.' + ' A sync task for this capsule was not recently invoked.' + ) + # final sync task end time, is the same as capsule's last_sync_time assert parse(sync_status['last_sync_time']) == parse(sync_status['last_sync_task']['ended_at']) - # last sync is on or after start_time - assert parse(sync_status['last_sync_time']) >= parse(start_time) + # check timedelta, that total time is not < 0s (last sync not before start time), and took less than timeout. + assert ( + timedelta(seconds=0) + <= parse(sync_status['last_sync_time']) - parse(start_time) + <= timedelta(seconds=timeout) + ), ( + f'Capsule: {capsule.hostname},\n last_sync_time: {sync_status["last_sync_time"]} was before the start time: {start_time},' + f' or duration exceeded timeout: {timeout}s' + ) + if active_sync: + # if we found in-progress task(s), last one was the final sync task for capsule + assert active_tasks[-1]['id'] == sync_status['last_sync_task']['id'] # no failed or active sync task(s) remaining - assert len(sync_status['active_sync_tasks']) == 0 assert len(sync_status['last_failed_sync_tasks']) == 0 + assert len(sync_status['active_sync_tasks']) == 0 + + return [active_sync, sync_status] # :returntype list: [boolean, dict] @pytest.mark.run_in_one_thread