From 86616b15592c28e48e9951d146c57a880bfb03fd Mon Sep 17 00:00:00 2001 From: "patchback[bot]" <45432694+patchback[bot]@users.noreply.github.com> Date: Sat, 14 Mar 2026 22:34:22 +0100 Subject: [PATCH] [PR #11592/2d685e7a backport][stable-12] test(monit): use uthelper (#11593) test(monit): use uthelper (#11592) (cherry picked from commit 2d685e7a85c067bb1589292ba5631351070ca8a8) Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com> --- tests/unit/plugins/modules/test_monit.py | 106 +-- tests/unit/plugins/modules/test_monit.yaml | 996 +++++++++++++++++++++ 2 files changed, 999 insertions(+), 103 deletions(-) create mode 100644 tests/unit/plugins/modules/test_monit.yaml diff --git a/tests/unit/plugins/modules/test_monit.py b/tests/unit/plugins/modules/test_monit.py index c6e3af5410..fc938e950e 100644 --- a/tests/unit/plugins/modules/test_monit.py +++ b/tests/unit/plugins/modules/test_monit.py @@ -7,7 +7,6 @@ from __future__ import annotations import unittest from unittest import mock -import pytest from ansible_collections.community.internal_test_tools.tests.unit.plugins.modules.utils import ( AnsibleExitJson, AnsibleFailJson, @@ -15,12 +14,9 @@ from ansible_collections.community.internal_test_tools.tests.unit.plugins.module from ansible_collections.community.general.plugins.modules import monit -TEST_OUTPUT = """ -%s '%s' - status %s - monitoring status Not monitored - monitoring mode active -""" +from .uthelper import RunCommandMock, UTHelper + +UTHelper.from_module(monit, __name__, mocks=[RunCommandMock]) class MonitTest(unittest.TestCase): @@ -39,29 +35,11 @@ class MonitTest(unittest.TestCase): side_effect = [side_effect] return mock.patch.object(self.monit, "get_status", side_effect=side_effect) - def test_change_state_success(self): - with self.patch_status([monit.Status("OK"), monit.Status("NOT_MONITORED")]): - with self.assertRaises(AnsibleExitJson): - self.monit.stop() - self.module.fail_json.assert_not_called() - self.module.run_command.assert_called_with(["monit", "stop", "processX"], check_rc=True) - def test_change_state_fail(self): with self.patch_status([monit.Status("OK")] * 3): with self.assertRaises(AnsibleFailJson): self.monit.stop() - def test_reload_fail(self): - self.module.run_command.return_value = (1, "stdout", "stderr") - with self.assertRaises(AnsibleFailJson): - self.monit.reload() - - def test_reload(self): - self.module.run_command.return_value = (0, "", "") - with self.patch_status(monit.Status("OK")): - with self.assertRaises(AnsibleExitJson): - self.monit.reload() - def test_wait_for_status_to_stop_pending(self): status = [ monit.Status("MISSING"), @@ -74,11 +52,6 @@ class MonitTest(unittest.TestCase): self.monit.wait_for_monit_to_stop_pending() self.assertEqual(get_status.call_count, len(status)) - def test_wait_for_status_change(self): - with self.patch_status([monit.Status("NOT_MONITORED"), monit.Status("OK")]) as get_status: - self.monit.wait_for_status_change(monit.Status("NOT_MONITORED")) - self.assertEqual(get_status.call_count, 2) - def test_wait_for_status_change_fail(self): with self.patch_status([monit.Status("OK")] * 3): with self.assertRaises(AnsibleFailJson): @@ -93,76 +66,3 @@ class MonitTest(unittest.TestCase): with self.patch_status([monit.Status("NOT_MONITORED")] * 3): with self.assertRaises(AnsibleFailJson): self.monit.monitor() - - def test_timeout(self): - self.monit.timeout = 0 - with self.patch_status(monit.Status("NOT_MONITORED").pending()): - with self.assertRaises(AnsibleFailJson): - self.monit.wait_for_monit_to_stop_pending() - - -BASIC_OUTPUT_CASES = [ - (TEST_OUTPUT % ("Process", "processX", member.value), monit.Status(member.name)) for member in monit.StatusValue -] - - -@pytest.mark.parametrize( - "output, expected", - BASIC_OUTPUT_CASES - + [ - ("", monit.Status("MISSING")), - (TEST_OUTPUT % ("Process", "processY", "OK"), monit.Status("MISSING")), - (TEST_OUTPUT % ("Process", "processX", "Not Monitored - start pending"), monit.Status("OK", is_pending=True)), - ( - TEST_OUTPUT % ("Process", "processX", "Monitored - stop pending"), - monit.Status("NOT_MONITORED", is_pending=True), - ), - (TEST_OUTPUT % ("Process", "processX", "Monitored - restart pending"), monit.Status("OK", is_pending=True)), - (TEST_OUTPUT % ("Process", "processX", "Not Monitored - monitor pending"), monit.Status("OK", is_pending=True)), - (TEST_OUTPUT % ("Process", "processX", "Does not exist"), monit.Status("DOES_NOT_EXIST")), - (TEST_OUTPUT % ("Process", "processX", "Not monitored"), monit.Status("NOT_MONITORED")), - (TEST_OUTPUT % ("Process", "processX", "Running"), monit.Status("OK")), - (TEST_OUTPUT % ("Process", "processX", "Execution failed | Does not exist"), monit.Status("EXECUTION_FAILED")), - (TEST_OUTPUT % ("Process", "processX", "Some Unknown Status"), monit.Status("EXECUTION_FAILED")), - ], -) -def test_parse_status(output, expected): - module = mock.MagicMock() - status = monit.Monit(module, "", "processX", 0)._parse_status(output, "") - assert status == expected - - -@pytest.mark.parametrize( - "output, expected", - BASIC_OUTPUT_CASES - + [ - (TEST_OUTPUT % ("Process", "processX", "OK"), monit.Status("OK")), - (TEST_OUTPUT % ("File", "processX", "OK"), monit.Status("OK")), - (TEST_OUTPUT % ("Fifo", "processX", "OK"), monit.Status("OK")), - (TEST_OUTPUT % ("Filesystem", "processX", "OK"), monit.Status("OK")), - (TEST_OUTPUT % ("Directory", "processX", "OK"), monit.Status("OK")), - (TEST_OUTPUT % ("Remote host", "processX", "OK"), monit.Status("OK")), - (TEST_OUTPUT % ("System", "processX", "OK"), monit.Status("OK")), - (TEST_OUTPUT % ("Program", "processX", "OK"), monit.Status("OK")), - (TEST_OUTPUT % ("Network", "processX", "OK"), monit.Status("OK")), - (TEST_OUTPUT % ("Unsupported", "processX", "OK"), monit.Status("MISSING")), - ], -) -def test_parse_status_supports_all_services(output, expected): - status = monit.Monit(None, "", "processX", 0)._parse_status(output, "") - assert status == expected - - -@pytest.mark.parametrize( - "output, expected", - [ - ("This is monit version 5.18.1", "5.18.1"), - ("This is monit version 12.18", "12.18"), - ("This is monit version 5.1.12", "5.1.12"), - ], -) -def test_parse_version(output, expected): - module = mock.MagicMock() - module.run_command.return_value = (0, output, "") - raw_version, version_tuple = monit.Monit(module, "", "processX", 0)._get_monit_version() - assert raw_version == expected diff --git a/tests/unit/plugins/modules/test_monit.yaml b/tests/unit/plugins/modules/test_monit.yaml new file mode 100644 index 0000000000..bc20c768bf --- /dev/null +++ b/tests/unit/plugins/modules/test_monit.yaml @@ -0,0 +1,996 @@ +# Copyright (c) Ansible project +# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) +# SPDX-License-Identifier: GPL-3.0-or-later +--- +anchors: + # version commands (version > 5.18 → adds -B flag to status/summary commands) + version_526: &version_526 + command: [/testbin/monit, -V] + environ: {check_rc: true} + rc: 0 + out: "This is monit version 5.26.0\n" + err: '' + version_518: &version_518 + command: [/testbin/monit, -V] + environ: {check_rc: true} + rc: 0 + out: "This is monit version 5.18.0\n" + err: '' + version_1218: &version_1218 + command: [/testbin/monit, -V] + environ: {check_rc: true} + rc: 0 + out: "This is monit version 12.18\n" + err: '' + version_5181: &version_5181 + command: [/testbin/monit, -V] + environ: {check_rc: true} + rc: 0 + out: "This is monit version 5.18.1\n" + err: '' + version_5112: &version_5112 + command: [/testbin/monit, -V] + environ: {check_rc: true} + rc: 0 + out: "This is monit version 5.1.12\n" + err: '' + + # summary commands (presence check) + summary_present_526: &summary_present_526 + command: [/testbin/monit, summary, -B] + environ: {check_rc: true} + rc: 0 + out: "processX\n" + err: '' + summary_not_present_526: &summary_not_present_526 + command: [/testbin/monit, summary, -B] + environ: {check_rc: true} + rc: 0 + out: "other_process\n" + err: '' + summary_present_518: &summary_present_518 + command: [/testbin/monit, summary] + environ: {check_rc: true} + rc: 0 + out: "processX\n" + err: '' + + # status commands with -B (version > 5.18) + status_ok_526: &status_ok_526 + command: [/testbin/monit, status, -B, processX] + environ: {check_rc: true} + rc: 0 + out: "Process 'processX'\n status OK\n" + err: '' + status_not_monitored_526: &status_not_monitored_526 + command: [/testbin/monit, status, -B, processX] + environ: {check_rc: true} + rc: 0 + out: "Process 'processX'\n status Not monitored\n" + err: '' + + # status commands without -B (version <= 5.18) + status_ok_no_b: &status_ok_no_b + command: [/testbin/monit, status, processX] + environ: {check_rc: true} + rc: 0 + out: "Process 'processX'\n status OK\n" + err: '' + status_not_monitored_no_b: &status_not_monitored_no_b + command: [/testbin/monit, status, processX] + environ: {check_rc: true} + rc: 0 + out: "Process 'processX'\n status Not monitored\n" + err: '' + + # status text variants for parse_status coverage (with -B) + status_ok_raw_526: &status_ok_raw_526 + command: [/testbin/monit, status, -B, processX] + environ: {check_rc: true} + rc: 0 + out: "Process 'processX'\n status ok\n" + err: '' + status_running_526: &status_running_526 + command: [/testbin/monit, status, -B, processX] + environ: {check_rc: true} + rc: 0 + out: "Process 'processX'\n status Running\n" + err: '' + status_not_monitored_raw_526: &status_not_monitored_raw_526 + command: [/testbin/monit, status, -B, processX] + environ: {check_rc: true} + rc: 0 + out: "Process 'processX'\n status not_monitored\n" + err: '' + status_missing_raw_526: &status_missing_raw_526 + command: [/testbin/monit, status, -B, processX] + environ: {check_rc: true} + rc: 0 + out: "Process 'processX'\n status missing\n" + err: '' + status_initializing_526: &status_initializing_526 + command: [/testbin/monit, status, -B, processX] + environ: {check_rc: true} + rc: 0 + out: "Process 'processX'\n status initializing\n" + err: '' + status_does_not_exist_raw_526: &status_does_not_exist_raw_526 + command: [/testbin/monit, status, -B, processX] + environ: {check_rc: true} + rc: 0 + out: "Process 'processX'\n status does_not_exist\n" + err: '' + status_does_not_exist_text_526: &status_does_not_exist_text_526 + command: [/testbin/monit, status, -B, processX] + environ: {check_rc: true} + rc: 0 + out: "Process 'processX'\n status Does not exist\n" + err: '' + status_exec_failed_raw_526: &status_exec_failed_raw_526 + command: [/testbin/monit, status, -B, processX] + environ: {check_rc: true} + rc: 0 + out: "Process 'processX'\n status execution_failed\n" + err: '' + status_exec_failed_pipe_526: &status_exec_failed_pipe_526 + command: [/testbin/monit, status, -B, processX] + environ: {check_rc: true} + rc: 0 + out: "Process 'processX'\n status Execution failed | Does not exist\n" + err: '' + status_unknown_526: &status_unknown_526 + command: [/testbin/monit, status, -B, processX] + environ: {check_rc: true} + rc: 0 + out: "Process 'processX'\n status Some Unknown Status\n" + err: '' + status_start_pending_526: &status_start_pending_526 + command: [/testbin/monit, status, -B, processX] + environ: {check_rc: true} + rc: 0 + out: "Process 'processX'\n status Not Monitored - start pending\n" + err: '' + status_stop_pending_526: &status_stop_pending_526 + command: [/testbin/monit, status, -B, processX] + environ: {check_rc: true} + rc: 0 + out: "Process 'processX'\n status Monitored - stop pending\n" + err: '' + status_restart_pending_526: &status_restart_pending_526 + command: [/testbin/monit, status, -B, processX] + environ: {check_rc: true} + rc: 0 + out: "Process 'processX'\n status Monitored - restart pending\n" + err: '' + status_monitor_pending_526: &status_monitor_pending_526 + command: [/testbin/monit, status, -B, processX] + environ: {check_rc: true} + rc: 0 + out: "Process 'processX'\n status Not Monitored - monitor pending\n" + err: '' + status_wrong_name_526: &status_wrong_name_526 + command: [/testbin/monit, status, -B, processX] + environ: {check_rc: true} + rc: 0 + out: "Process 'otherProcess'\n status OK\n" + err: '' + +test_cases: + # ------------------------------------------------------------------ no-change cases + - id: state_present_already_present + input: + name: processX + state: present + output: + changed: false + name: processX + state: present + mocks: + run_command: + - *version_526 + - *summary_present_526 + + - id: state_present_already_present_old_monit + input: + name: processX + state: present + output: + changed: false + name: processX + state: present + mocks: + run_command: + - *version_518 + - *summary_present_518 + + - id: state_started_already_running + # main(): is_process_present → wait_for_pending (get_status) → is_process_running (get_status) + # running=True, state in [started, monitored] → exit changed=False + input: + name: processX + state: started + output: + changed: false + name: processX + state: started + mocks: + run_command: + - *version_526 + - *summary_present_526 + - *status_ok_526 # wait_for_monit_to_stop_pending + - *status_ok_526 # is_process_running + + - id: state_monitored_already_running + input: + name: processX + state: monitored + output: + changed: false + name: processX + state: monitored + mocks: + run_command: + - *version_526 + - *summary_present_526 + - *status_ok_526 + - *status_ok_526 + + # ------------------------------------------------------------------ state changes + - id: state_stopped_currently_running + # change_state: get_status → stop → wait_for_status_change (status changes on 1st check) + input: + name: processX + state: stopped + output: + changed: true + name: processX + monit_version: "5.26.0" + state: stopped + mocks: + run_command: + - *version_526 + - *summary_present_526 + - *status_ok_526 # wait_for_monit_to_stop_pending + - *status_ok_526 # is_process_running (running=True) + - *status_ok_526 # change_state: current_status = get_status() + - command: [/testbin/monit, stop, processX] + environ: {check_rc: true} + rc: 0 + out: '' + err: '' + - *status_not_monitored_526 # wait_for_status_change: status changed → done + + - id: state_started_not_running + # process is not running → monit.start() → status changes to OK on 1st check + input: + name: processX + state: started + output: + changed: true + name: processX + monit_version: "5.26.0" + state: started + mocks: + run_command: + - *version_526 + - *summary_present_526 + - *status_not_monitored_526 # wait_for_monit_to_stop_pending + - *status_not_monitored_526 # is_process_running (running=False) + - *status_not_monitored_526 # change_state: current_status = get_status() + - command: [/testbin/monit, start, processX] + environ: {check_rc: true} + rc: 0 + out: '' + err: '' + - *status_ok_526 # wait_for_status_change: status changed → done + + - id: state_unmonitored_currently_running + input: + name: processX + state: unmonitored + output: + changed: true + name: processX + monit_version: "5.26.0" + state: unmonitored + mocks: + run_command: + - *version_526 + - *summary_present_526 + - *status_ok_526 # wait_for_monit_to_stop_pending + - *status_ok_526 # is_process_running (running=True) + - *status_ok_526 # change_state: current_status = get_status() + - command: [/testbin/monit, unmonitor, processX] + environ: {check_rc: true} + rc: 0 + out: '' + err: '' + - *status_not_monitored_526 # wait_for_status_change: status changed → done + + - id: state_monitored_not_running + # process not running → monit.monitor() → status changes to OK (invert_expected=True → success) + input: + name: processX + state: monitored + output: + changed: true + name: processX + monit_version: "5.26.0" + state: monitored + mocks: + run_command: + - *version_526 + - *summary_present_526 + - *status_not_monitored_526 # wait_for_monit_to_stop_pending + - *status_not_monitored_526 # is_process_running (running=False) + - *status_not_monitored_526 # change_state: current_status = get_status() + - command: [/testbin/monit, monitor, processX] + environ: {check_rc: true} + rc: 0 + out: '' + err: '' + - *status_ok_526 # wait_for_status_change: changed → done; match inverted → success + + - id: state_restarted + # restart works regardless of running state; process not running → restart → becomes OK + input: + name: processX + state: restarted + output: + changed: true + name: processX + monit_version: "5.26.0" + state: restarted + mocks: + run_command: + - *version_526 + - *summary_present_526 + - *status_not_monitored_526 # wait_for_monit_to_stop_pending + - *status_not_monitored_526 # is_process_running (running=False) + - *status_not_monitored_526 # change_state: current_status = get_status() + - command: [/testbin/monit, restart, processX] + environ: {check_rc: true} + rc: 0 + out: '' + err: '' + - *status_ok_526 # wait_for_status_change: changed → done; OK == OK → success + + # ------------------------------------------------------------------ reload + - id: state_reloaded + # reload exits before any presence/status checks; no version check either + input: + name: processX + state: reloaded + output: + changed: true + state: reloaded + mocks: + run_command: + - command: [/testbin/monit, reload] + environ: {} + rc: 0 + out: '' + err: '' + + # ------------------------------------------------------------------ present (not yet) + - id: state_present_not_yet_present + # not present in summary → Monit.present(): reload + summary check (present on 1st try) + input: + name: processX + state: present + output: + changed: true + name: processX + monit_version: "5.26.0" + state: present + mocks: + run_command: + - *version_526 + - *summary_not_present_526 # initial presence check → not present + - command: [/testbin/monit, reload, processX] + environ: {check_rc: true} + rc: 0 + out: '' + err: '' + - *summary_present_526 # while loop: present on first check → exit + + # ------------------------------------------------------------------ failure cases + - id: state_reloaded_fail + # reload returns rc=1 → fail_json("monit reload failed") + input: + name: processX + state: reloaded + output: + failed: true + mocks: + run_command: + - command: [/testbin/monit, reload] + environ: {} + rc: 1 + out: "stdout" + err: "stderr" + + - id: state_started_pending_timeout + # timeout=0 + status=MISSING (empty output) → wait_for_monit_to_stop_pending times out + input: + name: processX + state: started + timeout: 0 + output: + failed: true + mocks: + run_command: + - *version_526 + - *summary_present_526 + - command: [/testbin/monit, status, -B, processX] + environ: {check_rc: true} + rc: 0 + out: '' + err: '' + + - id: state_stopped_status_change_on_retry + # same as state_stopped_currently_running but status is unchanged on the first check + # in wait_for_status_change; changes only on the second check (one retry loop) + input: + name: processX + state: stopped + output: + changed: true + name: processX + monit_version: "5.26.0" + state: stopped + mocks: + run_command: + - *version_526 + - *summary_present_526 + - *status_ok_526 # wait_for_monit_to_stop_pending + - *status_ok_526 # is_process_running (running=True) + - *status_ok_526 # change_state: current_status = get_status() + - command: [/testbin/monit, stop, processX] + environ: {check_rc: true} + rc: 0 + out: '' + err: '' + - *status_ok_526 # wait_for_status_change: initial (same → enters loop) + - *status_not_monitored_526 # loop_count=1, validate=False → changed! + + # ------------------------------------------------------------------ check mode + - id: state_stopped_check_mode + # check mode: presence + pending + running checks happen, then exit_if_check_mode fires + flags: + check: true + input: + name: processX + state: stopped + output: + changed: true + mocks: + run_command: + - *version_526 + - *summary_present_526 + - *status_ok_526 # wait_for_monit_to_stop_pending + - *status_ok_526 # is_process_running (running=True) → exit_if_check_mode + + # ------------------------------------------------------------------ parse_status coverage + # Each case targets a specific status string → parsed Status → verifiable module behavior. + # "ok", "running" → OK → state=started, already running → changed=false (4 commands) + # "not_monitored_raw" → NOT_MONITORED → start → changed=true (7 commands) + # in waiting_status (missing, initializing, does_not_exist) → timeout=0 → fail (3 commands) + # EXECUTION_FAILED → not running → special fast path in wait_for_status_change (7 commands) + # pending → is_pending=True → timeout=0 → fail (3 commands) + + - id: parse_status_ok_raw + # "ok" (raw enum value, lowercase) → Status("OK") → running → no change + input: + name: processX + state: started + output: + changed: false + state: started + mocks: + run_command: + - *version_526 + - *summary_present_526 + - *status_ok_raw_526 + - *status_ok_raw_526 + + - id: parse_status_running + # "Running" → Status("OK") via the RUNNING→OK alias → running → no change + input: + name: processX + state: started + output: + changed: false + state: started + mocks: + run_command: + - *version_526 + - *summary_present_526 + - *status_running_526 + - *status_running_526 + + - id: parse_status_not_monitored_raw + # "not_monitored" (raw, underscore) → Status("NOT_MONITORED") → not running → start + input: + name: processX + state: started + output: + changed: true + state: started + mocks: + run_command: + - *version_526 + - *summary_present_526 + - *status_not_monitored_raw_526 # wait_for_monit_to_stop_pending + - *status_not_monitored_raw_526 # is_process_running (False) + - *status_not_monitored_raw_526 # change_state: current_status + - command: [/testbin/monit, start, processX] + environ: {check_rc: true} + rc: 0 + out: '' + err: '' + - *status_ok_526 + + - id: parse_status_missing_raw + # "missing" (raw enum value) → Status("MISSING") → in waiting_status → timeout + input: + name: processX + state: started + timeout: 0 + output: + failed: true + mocks: + run_command: + - *version_526 + - *summary_present_526 + - *status_missing_raw_526 + + - id: parse_status_wrong_name + # process name not found in output → Status("MISSING") → timeout + input: + name: processX + state: started + timeout: 0 + output: + failed: true + mocks: + run_command: + - *version_526 + - *summary_present_526 + - *status_wrong_name_526 + + - id: parse_status_initializing + # "initializing" → Status("INITIALIZING") → in waiting_status → timeout + input: + name: processX + state: started + timeout: 0 + output: + failed: true + mocks: + run_command: + - *version_526 + - *summary_present_526 + - *status_initializing_526 + + - id: parse_status_does_not_exist_raw + # "does_not_exist" (raw) → Status("DOES_NOT_EXIST") → in waiting_status → timeout + input: + name: processX + state: started + timeout: 0 + output: + failed: true + mocks: + run_command: + - *version_526 + - *summary_present_526 + - *status_does_not_exist_raw_526 + + - id: parse_status_does_not_exist_text + # "Does not exist" → DOES_NOT_EXIST (via space→underscore normalisation) → timeout + input: + name: processX + state: started + timeout: 0 + output: + failed: true + mocks: + run_command: + - *version_526 + - *summary_present_526 + - *status_does_not_exist_text_526 + + - id: parse_status_exec_failed_raw + # "execution_failed" → EXECUTION_FAILED → not running, but wait_for_status_change + # returns immediately (special case: current_status.value == EXECUTION_FAILED) + input: + name: processX + state: started + output: + changed: true + state: started + mocks: + run_command: + - *version_526 + - *summary_present_526 + - *status_exec_failed_raw_526 # wait_for_monit_to_stop_pending (not in waiting_status) + - *status_exec_failed_raw_526 # is_process_running (False) + - *status_exec_failed_raw_526 # change_state: current_status + - command: [/testbin/monit, start, processX] + environ: {check_rc: true} + rc: 0 + out: '' + err: '' + - *status_ok_526 # wait_for_status_change returns immediately (EXECUTION_FAILED) + + - id: parse_status_exec_failed_pipe + # "Execution failed | Does not exist" → EXECUTION_FAILED (regex stops before |) + input: + name: processX + state: started + output: + changed: true + state: started + mocks: + run_command: + - *version_526 + - *summary_present_526 + - *status_exec_failed_pipe_526 + - *status_exec_failed_pipe_526 + - *status_exec_failed_pipe_526 + - command: [/testbin/monit, start, processX] + environ: {check_rc: true} + rc: 0 + out: '' + err: '' + - *status_ok_526 + + - id: parse_status_unknown + # "Some Unknown Status" → EXECUTION_FAILED (via module.warn + fallback) + input: + name: processX + state: started + output: + changed: true + state: started + mocks: + run_command: + - *version_526 + - *summary_present_526 + - *status_unknown_526 + - *status_unknown_526 + - *status_unknown_526 + - command: [/testbin/monit, start, processX] + environ: {check_rc: true} + rc: 0 + out: '' + err: '' + - *status_ok_526 + + - id: parse_status_start_pending + # "Not Monitored - start pending" → Status("OK", is_pending=True) → timeout + input: + name: processX + state: started + timeout: 0 + output: + failed: true + mocks: + run_command: + - *version_526 + - *summary_present_526 + - *status_start_pending_526 + + - id: parse_status_stop_pending + # "Monitored - stop pending" → Status("NOT_MONITORED", is_pending=True) → timeout + input: + name: processX + state: started + timeout: 0 + output: + failed: true + mocks: + run_command: + - *version_526 + - *summary_present_526 + - *status_stop_pending_526 + + - id: parse_status_restart_pending + # "Monitored - restart pending" → Status("OK", is_pending=True) → timeout + input: + name: processX + state: started + timeout: 0 + output: + failed: true + mocks: + run_command: + - *version_526 + - *summary_present_526 + - *status_restart_pending_526 + + - id: parse_status_monitor_pending + # "Not Monitored - monitor pending" → Status("OK", is_pending=True) → timeout + input: + name: processX + state: started + timeout: 0 + output: + failed: true + mocks: + run_command: + - *version_526 + - *summary_present_526 + - *status_monitor_pending_526 + + # ------------------------------------------------------------------ parse_service_types coverage + # Each recognised service type: process name found → status OK → running → changed=false + # "Unsupported" is not in MONIT_SERVICES → MISSING → timeout + + - id: parse_service_file + input: + name: processX + state: started + output: + changed: false + state: started + mocks: + run_command: + - *version_526 + - *summary_present_526 + - command: [/testbin/monit, status, -B, processX] + environ: {check_rc: true} + rc: 0 + out: "File 'processX'\n status OK\n" + err: '' + - command: [/testbin/monit, status, -B, processX] + environ: {check_rc: true} + rc: 0 + out: "File 'processX'\n status OK\n" + err: '' + + - id: parse_service_fifo + input: + name: processX + state: started + output: + changed: false + state: started + mocks: + run_command: + - *version_526 + - *summary_present_526 + - command: [/testbin/monit, status, -B, processX] + environ: {check_rc: true} + rc: 0 + out: "Fifo 'processX'\n status OK\n" + err: '' + - command: [/testbin/monit, status, -B, processX] + environ: {check_rc: true} + rc: 0 + out: "Fifo 'processX'\n status OK\n" + err: '' + + - id: parse_service_filesystem + input: + name: processX + state: started + output: + changed: false + state: started + mocks: + run_command: + - *version_526 + - *summary_present_526 + - command: [/testbin/monit, status, -B, processX] + environ: {check_rc: true} + rc: 0 + out: "Filesystem 'processX'\n status OK\n" + err: '' + - command: [/testbin/monit, status, -B, processX] + environ: {check_rc: true} + rc: 0 + out: "Filesystem 'processX'\n status OK\n" + err: '' + + - id: parse_service_directory + input: + name: processX + state: started + output: + changed: false + state: started + mocks: + run_command: + - *version_526 + - *summary_present_526 + - command: [/testbin/monit, status, -B, processX] + environ: {check_rc: true} + rc: 0 + out: "Directory 'processX'\n status OK\n" + err: '' + - command: [/testbin/monit, status, -B, processX] + environ: {check_rc: true} + rc: 0 + out: "Directory 'processX'\n status OK\n" + err: '' + + - id: parse_service_remote_host + input: + name: processX + state: started + output: + changed: false + state: started + mocks: + run_command: + - *version_526 + - *summary_present_526 + - command: [/testbin/monit, status, -B, processX] + environ: {check_rc: true} + rc: 0 + out: "Remote host 'processX'\n status OK\n" + err: '' + - command: [/testbin/monit, status, -B, processX] + environ: {check_rc: true} + rc: 0 + out: "Remote host 'processX'\n status OK\n" + err: '' + + - id: parse_service_system + input: + name: processX + state: started + output: + changed: false + state: started + mocks: + run_command: + - *version_526 + - *summary_present_526 + - command: [/testbin/monit, status, -B, processX] + environ: {check_rc: true} + rc: 0 + out: "System 'processX'\n status OK\n" + err: '' + - command: [/testbin/monit, status, -B, processX] + environ: {check_rc: true} + rc: 0 + out: "System 'processX'\n status OK\n" + err: '' + + - id: parse_service_program + input: + name: processX + state: started + output: + changed: false + state: started + mocks: + run_command: + - *version_526 + - *summary_present_526 + - command: [/testbin/monit, status, -B, processX] + environ: {check_rc: true} + rc: 0 + out: "Program 'processX'\n status OK\n" + err: '' + - command: [/testbin/monit, status, -B, processX] + environ: {check_rc: true} + rc: 0 + out: "Program 'processX'\n status OK\n" + err: '' + + - id: parse_service_network + input: + name: processX + state: started + output: + changed: false + state: started + mocks: + run_command: + - *version_526 + - *summary_present_526 + - command: [/testbin/monit, status, -B, processX] + environ: {check_rc: true} + rc: 0 + out: "Network 'processX'\n status OK\n" + err: '' + - command: [/testbin/monit, status, -B, processX] + environ: {check_rc: true} + rc: 0 + out: "Network 'processX'\n status OK\n" + err: '' + + - id: parse_service_unsupported + # "Unsupported" not in MONIT_SERVICES → _parse_status returns MISSING → timeout + input: + name: processX + state: started + timeout: 0 + output: + failed: true + mocks: + run_command: + - *version_526 + - *summary_present_526 + - command: [/testbin/monit, status, -B, processX] + environ: {check_rc: true} + rc: 0 + out: "Unsupported 'processX'\n status OK\n" + err: '' + + # ------------------------------------------------------------------ parse_version coverage + # state=stopped (running process) exercises exit_success() which includes monit_version. + # Commands with/without -B reveal whether the version tuple was parsed correctly. + + - id: parse_version_1218 + # "12.18" → (12, 18) > (5, 18) → -B added; monit_version="12.18" in output + input: + name: processX + state: stopped + output: + changed: true + monit_version: "12.18" + state: stopped + mocks: + run_command: + - *version_1218 + - *summary_present_526 # -B because (12,18) > (5,18) + - *status_ok_526 + - *status_ok_526 + - *status_ok_526 + - command: [/testbin/monit, stop, processX] + environ: {check_rc: true} + rc: 0 + out: '' + err: '' + - *status_not_monitored_526 + + - id: parse_version_5181 + # "5.18.1" → (5, 18) not > (5, 18) → no -B; monit_version="5.18.1" in output + input: + name: processX + state: stopped + output: + changed: true + monit_version: "5.18.1" + state: stopped + mocks: + run_command: + - *version_5181 + - *summary_present_518 # no -B because (5,18) == (5,18) + - *status_ok_no_b + - *status_ok_no_b + - *status_ok_no_b + - command: [/testbin/monit, stop, processX] + environ: {check_rc: true} + rc: 0 + out: '' + err: '' + - *status_not_monitored_no_b + + - id: parse_version_5112 + # "5.1.12" → (5, 1) not > (5, 18) → no -B; monit_version="5.1.12" in output + input: + name: processX + state: stopped + output: + changed: true + monit_version: "5.1.12" + state: stopped + mocks: + run_command: + - *version_5112 + - *summary_present_518 # no -B because (5,1) < (5,18) + - *status_ok_no_b + - *status_ok_no_b + - *status_ok_no_b + - command: [/testbin/monit, stop, processX] + environ: {check_rc: true} + rc: 0 + out: '' + err: '' + - *status_not_monitored_no_b