Commit 4f1a6a6c authored by nimrod's avatar nimrod
Browse files

Progress.

- More tests, now using mocks.
- Silence some linter warnings.
- Start thinking about parsing perfdata.
parent 343ea3da
Loading
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -62,6 +62,7 @@ repos:
        additional_dependencies:
          - bandit
          - pyroma
        exclude: ^tests/.*

  - repo: https://gitlab.com/pycqa/flake8.git
    rev: 3.9.2
+1 −0
Original line number Diff line number Diff line
"""My Nagios plugin wrapper."""
# pylint: disable=logging-fstring-interpolation
__version__ = "0.1.0"

import argparse
+13 −4
Original line number Diff line number Diff line
"""Nagios check implementation.

Based on the specification from
https://assets.nagios.com/downloads/nagioscore/docs/nagioscore/3/en/pluginapi.html"""
https://assets.nagios.com/downloads/nagioscore/docs/nagioscore/3/en/pluginapi.html
"""
# pylint: disable=logging-fstring-interpolation

import collections
import enum
import logging
import subprocess
import subprocess  # nosec

DEFAULT_TIMEOUT = 10  # In seconds.

@@ -19,7 +22,13 @@ class NagiosCode(enum.IntEnum):
    UNKNOWN = 3


PerfData = collections.namedtuple(
    "PerfData", ["name", "value", "unit", "warning", "critical", "min", "max"]
)


class Check:
    # pylint: disable=invalid-name
    """Nagios check using a plugin."""

    Command = None
@@ -32,7 +41,7 @@ class Check:
    stderr = None
    _stdout = None

    def __init__(self, command, args):
    def __init__(self, command, args=None):
        if not command:
            raise ValueError("Command is empty.")
        self.Command = command
@@ -55,7 +64,7 @@ class Check:
        ] + self.Arguments
        logging.info(f"Running command {_cmd}.")
        try:
            proc = subprocess.run(
            proc = subprocess.run(  # nosec
                [
                    self.Command,
                ]
+62 −1
Original line number Diff line number Diff line
import subprocess
import unittest.mock

import pytest

from mnpw import nagios

OUTPUT_1 = """DISK OK - free space: / 3326 MB (56%);"""
OUTPUT_2 = (
    """ DISK OK - free space: / 3326 MB (56%); | /=2643MB;5948;5958;0;5968"""
)
OUTPUT_3 = """\
DISK OK - free space: / 3326 MB (56%); | /=2643MB;5948;5958;0;5968
/ 15272 MB (77%);
/boot 68 MB (69%);
/home 69357 MB (27%);
/var/log 819 MB (84%); | /boot=68MB;88;93;0;98
/home=69357MB;253404;253409;0;253414
/var/log=818MB;970;975;0;980
"""


@pytest.mark.parametrize(
    "command,args,exit_code",
@@ -30,4 +47,48 @@ def test_check_timeout():
    """Test check with a timed out command."""
    check = nagios.Check("sleep", ["20"])
    with pytest.raises(RuntimeError):
        check.run(3)
        check.run(timeout=3)


def _mock_run(*args, **kwargs):
    """Mock subprocess' run."""
    return unittest.mock.patch.object(
        nagios.subprocess,
        "run",
        *args,
        **kwargs,
    )


@pytest.mark.parametrize(
    "exception",
    [
        FileNotFoundError,
        subprocess.TimeoutExpired(cmd="true", timeout=nagios.DEFAULT_TIMEOUT),
    ],
)
def test_check_exceptions(exception):
    """Test handling of subprocess' run exceptions.
    See
    https://docs.python.org/3/library/subprocess.html?highlight=popen#subprocess.SubprocessError
    """
    check = nagios.Check("true")
    with _mock_run(side_effect=exception), pytest.raises(RuntimeError):
        check.run()


@pytest.mark.parametrize("output", [OUTPUT_1, OUTPUT_2, OUTPUT_3])
def test_output_parsing(output):
    """Test parsing of plugin output."""
    check = nagios.Check("true")
    proc = subprocess.CompletedProcess(
        [
            "true",
        ],
        0,
        output,
        "",
    )
    with _mock_run(return_value=proc):
        check.run()
        # TODO: validate something.