diff --git a/changelogs/fragments/delay_type.yml b/changelogs/fragments/delay_type.yml new file mode 100644 index 00000000000..03b44dc0989 --- /dev/null +++ b/changelogs/fragments/delay_type.yml @@ -0,0 +1,2 @@ +bugfixes: + - delay keyword is now a float, matching the underlying 'time' API and user expectations. diff --git a/lib/ansible/playbook/task.py b/lib/ansible/playbook/task.py index 4ff105c5db9..431501b4af5 100644 --- a/lib/ansible/playbook/task.py +++ b/lib/ansible/playbook/task.py @@ -72,7 +72,7 @@ class Task(Base, Conditional, Taggable, CollectionSearch, Notifiable, Delegatabl async_val = NonInheritableFieldAttribute(isa='int', default=0, alias='async') changed_when = NonInheritableFieldAttribute(isa='list', default=list) - delay = NonInheritableFieldAttribute(isa='int', default=5) + delay = NonInheritableFieldAttribute(isa='float', default=5) failed_when = NonInheritableFieldAttribute(isa='list', default=list) loop = NonInheritableFieldAttribute(isa='list') loop_control = NonInheritableFieldAttribute(isa='class', class_type=LoopControl, default=LoopControl) diff --git a/test/units/playbook/test_task.py b/test/units/playbook/test_task.py index 6eb3bf22107..f00485cbc33 100644 --- a/test/units/playbook/test_task.py +++ b/test/units/playbook/test_task.py @@ -1,28 +1,15 @@ -# (c) 2012-2014, Michael DeHaan -# -# This file is part of Ansible -# -# Ansible is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# Ansible is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with Ansible. If not, see . - +# Copyright: (c) Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) from __future__ import annotations import unittest + from unittest.mock import patch + +from ansible import errors +from ansible.parsing.yaml import objects from ansible.playbook.task import Task from ansible.plugins.loader import init_plugin_loader -from ansible.parsing.yaml import objects -from ansible import errors basic_command_task = dict( @@ -42,7 +29,7 @@ kv_bad_args_ds = {'apk': 'sdfs sf sdf 37'} class TestTask(unittest.TestCase): def setUp(self): - pass + self._task_base = {'name': 'test', 'action': 'debug'} def tearDown(self): pass @@ -62,7 +49,7 @@ class TestTask(unittest.TestCase): def test_load_task_simple(self): t = Task.load(basic_command_task) assert t is not None - self.assertEqual(t.name, basic_command_task['name']) + self.assertEqual(t.get_name(), basic_command_task['name']) self.assertEqual(t.action, 'command') self.assertEqual(t.args, dict(_raw_params='echo hi')) @@ -91,9 +78,41 @@ class TestTask(unittest.TestCase): self.assertEqual(cm.exception.message.count('The error appears to be in'), 1) def test_task_auto_name(self): - assert 'name' not in kv_command_task - Task.load(kv_command_task) - # self.assertEqual(t.name, 'shell echo hi') + self.assertNotIn('name', kv_command_task) + t = Task.load(kv_command_task) + self.assertEqual(t.get_name(), 'command') + + def test_delay(self): + good_params = [ + (0, 0), + (0.1, 0.1), + ('0.3', 0.3), + ('0.03', 0.03), + ('12', 12), + (12, 12), + (1.2, 1.2), + ('1.2', 1.2), + ('1.0', 1), + ] + for delay, expected in good_params: + with self.subTest(f'type "{type(delay)}" was not cast to float', delay=delay, expected=expected): + p = dict(delay=delay) + p.update(self._task_base) + t = Task().load_data(p) + self.assertEqual(t.get_validated_value('delay', t.fattributes.get('delay'), delay, None), expected) + + bad_params = [ + ('E', ValueError), + ('1.E', ValueError), + ('E.1', ValueError), + ] + for delay, expected in bad_params: + with self.subTest(f'type "{type(delay)} was cast to float w/o error', delay=delay, expected=expected): + p = dict(delay=delay) + p.update(self._task_base) + t = Task().load_data(p) + with self.assertRaises(expected): + dummy = t.get_validated_value('delay', t.fattributes.get('delay'), delay, None) def test_task_auto_name_with_role(self): pass