diff --git a/doc/plugins.md b/doc/plugins.md index e1845a7..95124f4 100644 --- a/doc/plugins.md +++ b/doc/plugins.md @@ -82,14 +82,17 @@ may occur multiple times): - The `label` attribute describes the output. Example: ```xml - /opt/xensource/bin/xe host-data-source-list host=$(/opt/xensource/bin/xe pool-list params=master --minimal) + /opt/xensource/bin/xe host-data-source-list + host=$(/opt/xensource/bin/xe pool-list params=master --minimal) ``` ### Example `stuff.xml` file from the `xapi` bugtool Plugin ```xml -/opt/xensource/bin/xe sr-list --minimal | tr , '\n' | xargs --verbose -n 1 -I {} /opt/xensource/bin/xe sr-data-source-list uuid={} 2>&1 +/opt/xensource/bin/xe sr-list --minimal | + tr , '\n' | xargs --verbose -n 1 -I {} /opt/xensource/bin/xe sr-data-source-list + uuid={} 2>&1 /etc/stunnel/xapi.conf /var/lib/corosync /etc/xen/scripts diff --git a/tests/unit/conftest.py b/tests/unit/conftest.py index 91aa17c..a4dcfa4 100644 --- a/tests/unit/conftest.py +++ b/tests/unit/conftest.py @@ -176,3 +176,22 @@ def isolated_bugtool(bugtool_log): os.chmod(".", 0o777) # nosec # restore write permissions (for cleanup) # upon return, bugtool_log continues with its cleanup + + +@pytest.fixture(scope="function") +def bugtool_fixture(isolated_bugtool): + """ + Fixture that wraps isolated_bugtool and restores its state after each test. + """ + + # Assert that isolated_bugtool is pristine and we have a clean state to start: + assert isolated_bugtool.data == {} + assert isolated_bugtool.entries is None + + yield isolated_bugtool # runs the test case in the read-only directory + + # Restore isolated_bugtool to its pristine state: + isolated_bugtool.data = {} + isolated_bugtool.entries = None + + # upon return, isolated_bugtool continues with its cleanup diff --git a/tests/unit/test_cmd_output.py b/tests/unit/test_cmd_output.py new file mode 100644 index 0000000..fa3bad1 --- /dev/null +++ b/tests/unit/test_cmd_output.py @@ -0,0 +1,110 @@ +"""tests/unit/test_cmd_output.py: Unit-Test bugtool.cmd_output()""" + + +def test_cmd_output_mismatching_cap(bugtool_fixture): + """Assert that mismatching cap causes no extension of bugtool.data:""" + + # Prepare that mismatching cap causes no output in bugtool.data: + bugtool_fixture.entries = [bugtool_fixture.CAP_PAM] + + # Act + bugtool_fixture.cmd_output(bugtool_fixture.CAP_XENSERVER_LOGS, ["/bin/sh"]) + + # Assert that the command is not added to data + assert bugtool_fixture.data == {} + + +def check_cmd_output_data(bugtool, command, label=None, filter_func=None): + """ + Assert that cmd_output() stores the expected command in bugtool.data + It works by setting bugtool.data and bugtool.entries to fixed values + and asserting the expected bugtool.data after the check. + + Use this function only with bugtool_fixture which saves and restores + the original values of these variables to avoid affecting other test cases. + """ + + # Prepare + bugtool.entries = [bugtool.CAP_PAM] + bugtool.data = {} + + # Act + bugtool.cmd_output(bugtool.entries[0], command, label, filter=filter_func) + + # Assert + assert bugtool.data == { + label + or command: { + "filter": filter_func, + "cap": bugtool.entries[0], + "cmd_args": command, + } + } + + +def test_cmd_output_command(bugtool_fixture): + """Test how cmd_output() handles a command which can be found""" + + check_cmd_output_data(bugtool_fixture, "pwd --version") + + +def test_cmd_output_command_label(bugtool_fixture): + """Test how cmd_output() handles a command which can be found with a label""" + + check_cmd_output_data(bugtool_fixture, "pwd --version", "label") + + +def test_cmd_output_missing_command(bugtool_fixture): + """Test how cmd_output() handles a missing command""" + + check_cmd_output_data(bugtool_fixture, "/missing-cmd arg") + + +def test_cmd_output_missing_command_with_label(bugtool_fixture): + """Test how cmd_output() handles a missing command with a label""" + + check_cmd_output_data(bugtool_fixture, "/missing-cmd arg", "label") + + +def test_cmd_output_multiple_calls(bugtool_fixture): + """Assert the cumulative effect of multiple cmd_output() calls.""" + + # Prepare + # + cap1 = bugtool_fixture.CAP_OEM + cap2 = bugtool_fixture.CAP_PAM + bugtool_fixture.entries = [cap1, cap2] + + def mock_filter(): + """No-op mock filter used in tests for asserting it in bugtool_fixture.data""" + + # Act + # + cmd1 = ["/usr/bin/pwd", "--version"] + cmd2 = ["/missing-cmd", "arg1", "arg2"] + bugtool_fixture.cmd_output("not_an_activated_capability", cmd1) + bugtool_fixture.cmd_output(cap1, [cmd1[0]], filter=mock_filter) + bugtool_fixture.cmd_output(cap1, cmd1) + bugtool_fixture.cmd_output(cap2, cmd2) + + # Assert + # + assert bugtool_fixture.data == { + "pwd": { + "cap": cap1, + "cmd_args": ["/usr/bin/pwd"], + "filter": mock_filter, + }, + # At the moment, we also add commands which are missing on the system to data + "missing-cmd arg1 arg2": { + "cap": cap2, + "cmd_args": cmd2, + "filter": None, + }, + # Uses command as string without path as key when no label is set + "pwd --version": { + "cap": cap1, + "cmd_args": cmd1, + "filter": None, + }, + }