fceb71128e
So I thought I fixed it before, but there's still one location where the `rc` value is influential to decide whether a task failed or not. We already established in #24867 that it is up to the module to decide what the return code actually means, not the task executor. We modified the existing modules to move that logic into the module (eg. for command, shell, etc.) This relates to the integration tests of win_robocopy, where different return codes have different meanings: - 0 -- No files copied. - 1 -- Files copied successfully! (changed) - 2 -- Some Extra files or directories were detected. No files were copied. (warning) - 3 -- (2+1) Some files were copied. Additional files were present. (changed) - 4 -- Some mismatched files or directories were detected. Housekeeping might be required! (changed + warning) - 5 -- (4+1) Some files were copied. Some files were mismatched. (changed + warning) - 6 -- (4+2) Additional files and mismatched files exist. No files were copied. (warning) - 7 -- (4+1+2) Files were copied, a file mismatch was present, and additional files were present. (changed + warning) - 8 -- Some files or directories could not be copied! (changed + failed) - 9 - 15 -- Fatal error. Check log message! (failed) - 16 -- Serious Error! No files were copied! Do you have permissions to access $src and $dest? (failed) This also fixes #24652
140 lines
5.5 KiB
Python
140 lines
5.5 KiB
Python
# (c) 2016, James Cammarata <jimi@sngx.net>
|
|
#
|
|
# 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 <http://www.gnu.org/licenses/>.
|
|
|
|
# Make coding more python3-ish
|
|
from __future__ import (absolute_import, division, print_function)
|
|
__metaclass__ = type
|
|
|
|
from ansible.compat.tests import unittest
|
|
from ansible.compat.tests.mock import patch, MagicMock
|
|
|
|
from ansible.executor.task_result import TaskResult
|
|
|
|
|
|
class TestTaskResult(unittest.TestCase):
|
|
def test_task_result_basic(self):
|
|
mock_host = MagicMock()
|
|
mock_task = MagicMock()
|
|
|
|
# test loading a result with a dict
|
|
tr = TaskResult(mock_host, mock_task, dict())
|
|
|
|
# test loading a result with a JSON string
|
|
with patch('ansible.parsing.dataloader.DataLoader.load') as p:
|
|
tr = TaskResult(mock_host, mock_task, '{}')
|
|
|
|
def test_task_result_is_changed(self):
|
|
mock_host = MagicMock()
|
|
mock_task = MagicMock()
|
|
|
|
# test with no changed in result
|
|
tr = TaskResult(mock_host, mock_task, dict())
|
|
self.assertFalse(tr.is_changed())
|
|
|
|
# test with changed in the result
|
|
tr = TaskResult(mock_host, mock_task, dict(changed=True))
|
|
self.assertTrue(tr.is_changed())
|
|
|
|
# test with multiple results but none changed
|
|
mock_task.loop = 'foo'
|
|
tr = TaskResult(mock_host, mock_task, dict(results=[dict(foo='bar'), dict(bam='baz'), True]))
|
|
self.assertFalse(tr.is_changed())
|
|
|
|
# test with multiple results and one changed
|
|
mock_task.loop = 'foo'
|
|
tr = TaskResult(mock_host, mock_task, dict(results=[dict(changed=False), dict(changed=True), dict(some_key=False)]))
|
|
self.assertTrue(tr.is_changed())
|
|
|
|
def test_task_result_is_skipped(self):
|
|
mock_host = MagicMock()
|
|
mock_task = MagicMock()
|
|
|
|
# test with no skipped in result
|
|
tr = TaskResult(mock_host, mock_task, dict())
|
|
self.assertFalse(tr.is_skipped())
|
|
|
|
# test with skipped in the result
|
|
tr = TaskResult(mock_host, mock_task, dict(skipped=True))
|
|
self.assertTrue(tr.is_skipped())
|
|
|
|
# test with multiple results but none skipped
|
|
mock_task.loop = 'foo'
|
|
tr = TaskResult(mock_host, mock_task, dict(results=[dict(foo='bar'), dict(bam='baz'), True]))
|
|
self.assertFalse(tr.is_skipped())
|
|
|
|
# test with multiple results and one skipped
|
|
mock_task.loop = 'foo'
|
|
tr = TaskResult(mock_host, mock_task, dict(results=[dict(skipped=False), dict(skipped=True), dict(some_key=False)]))
|
|
self.assertFalse(tr.is_skipped())
|
|
|
|
# test with multiple results and all skipped
|
|
mock_task.loop = 'foo'
|
|
tr = TaskResult(mock_host, mock_task, dict(results=[dict(skipped=True), dict(skipped=True), dict(skipped=True)]))
|
|
self.assertTrue(tr.is_skipped())
|
|
|
|
# test with multiple squashed results (list of strings)
|
|
# first with the main result having skipped=False
|
|
mock_task.loop = 'foo'
|
|
tr = TaskResult(mock_host, mock_task, dict(results=["a", "b", "c"], skipped=False))
|
|
self.assertFalse(tr.is_skipped())
|
|
# then with the main result having skipped=True
|
|
tr = TaskResult(mock_host, mock_task, dict(results=["a", "b", "c"], skipped=True))
|
|
self.assertTrue(tr.is_skipped())
|
|
|
|
def test_task_result_is_unreachable(self):
|
|
mock_host = MagicMock()
|
|
mock_task = MagicMock()
|
|
|
|
# test with no unreachable in result
|
|
tr = TaskResult(mock_host, mock_task, dict())
|
|
self.assertFalse(tr.is_unreachable())
|
|
|
|
# test with unreachable in the result
|
|
tr = TaskResult(mock_host, mock_task, dict(unreachable=True))
|
|
self.assertTrue(tr.is_unreachable())
|
|
|
|
# test with multiple results but none unreachable
|
|
mock_task.loop = 'foo'
|
|
tr = TaskResult(mock_host, mock_task, dict(results=[dict(foo='bar'), dict(bam='baz'), True]))
|
|
self.assertFalse(tr.is_unreachable())
|
|
|
|
# test with multiple results and one unreachable
|
|
mock_task.loop = 'foo'
|
|
tr = TaskResult(mock_host, mock_task, dict(results=[dict(unreachable=False), dict(unreachable=True), dict(some_key=False)]))
|
|
self.assertTrue(tr.is_unreachable())
|
|
|
|
def test_task_result_is_failed(self):
|
|
mock_host = MagicMock()
|
|
mock_task = MagicMock()
|
|
|
|
# test with no failed in result
|
|
tr = TaskResult(mock_host, mock_task, dict())
|
|
self.assertFalse(tr.is_failed())
|
|
|
|
# test failed result with rc values (should not matter)
|
|
tr = TaskResult(mock_host, mock_task, dict(rc=0))
|
|
self.assertFalse(tr.is_failed())
|
|
tr = TaskResult(mock_host, mock_task, dict(rc=1))
|
|
self.assertFalse(tr.is_failed())
|
|
|
|
# test with failed in result
|
|
tr = TaskResult(mock_host, mock_task, dict(failed=True))
|
|
self.assertTrue(tr.is_failed())
|
|
|
|
# test with failed_when in result
|
|
tr = TaskResult(mock_host, mock_task, dict(failed_when_result=True))
|
|
self.assertTrue(tr.is_failed())
|