mirror of
https://github.com/saltstack/salt.git
synced 2025-04-17 10:10:20 +00:00
548 lines
20 KiB
Python
548 lines
20 KiB
Python
import copy
|
|
|
|
import pytest
|
|
import salt.config
|
|
import salt.output.highstate as highstate
|
|
from salt.utils.odict import OrderedDict
|
|
from tests.support.mock import patch
|
|
|
|
|
|
@pytest.fixture
|
|
def configure_loader_modules():
|
|
minion_opts = salt.config.DEFAULT_MINION_OPTS.copy()
|
|
minion_opts.update({"color": False, "state_output_pct": True})
|
|
return {highstate: {"__opts__": minion_opts}}
|
|
|
|
|
|
@pytest.mark.parametrize("data", [None, {"return": None}, {"return": {"data": None}}])
|
|
def test_when_data_result_is_None_output_should_be_string_None(data):
|
|
expected_output = "None"
|
|
|
|
actual_output = highstate.output(data=data)
|
|
|
|
assert actual_output == expected_output
|
|
|
|
|
|
def test_when_data_is_dict_with_return_key_and_return_value_has_data_key_and_data_dict_has_one_dict_element_with_jid_and_fun_keys_and_return_value_is_None_then_output_should_return_literal_None_string():
|
|
|
|
expected_output = "None"
|
|
data = {
|
|
"return": {
|
|
"data": {
|
|
"foo bar quux fnord": {
|
|
"jid": "fnordy fnordy fnordy",
|
|
"fun": "fnordy fnordy fnord",
|
|
"return": {"data": None},
|
|
},
|
|
}
|
|
},
|
|
}
|
|
|
|
actual_output = highstate.output(data=data)
|
|
|
|
assert actual_output == expected_output
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"return_value",
|
|
[42, "fnord"],
|
|
)
|
|
def test_when_data_is_dict_with_return_key_and_return_value_has_data_key_and_data_dict_has_one_dict_element_with_jid_and_fun_keys_and_return_value_is_int_or_str_that_value_should_be_returned(
|
|
return_value,
|
|
):
|
|
|
|
expected_output = return_value
|
|
data = {
|
|
"return": {
|
|
"data": {
|
|
"foo bar quux fnord": {
|
|
"jid": "fnordy fnordy fnordy",
|
|
"fun": "fnordy fnordy fnord",
|
|
"return": {"data": return_value},
|
|
},
|
|
}
|
|
},
|
|
}
|
|
|
|
actual_output = highstate.output(data=data)
|
|
|
|
assert actual_output == expected_output
|
|
|
|
|
|
def test_when_orchestrator_output_retcode_in_data_the_retcode_should_be_removed():
|
|
data = {"something_master": None, "retcode": 42}
|
|
|
|
actual_output = highstate.output(data)
|
|
|
|
assert "retcode" not in data
|
|
|
|
|
|
def test_when_more_than_one_local_master_retcode_should_not_be_removed():
|
|
expected_retcode = 42
|
|
data = {
|
|
"something_master": None,
|
|
"another_master": None,
|
|
"retcode": expected_retcode,
|
|
}
|
|
|
|
actual_output = highstate.output(data)
|
|
|
|
assert data["retcode"] == expected_retcode
|
|
|
|
|
|
def test_pct_summary_output():
|
|
data = {
|
|
"data": {
|
|
"master": {
|
|
"salt_|-call_sleep_state_|-call_sleep_state_|-state": {
|
|
"__id__": "call_sleep_state",
|
|
"__jid__": "20170418153529810135",
|
|
"__run_num__": 0,
|
|
"__sls__": "orch.simple",
|
|
"changes": {
|
|
"out": "highstate",
|
|
"ret": {
|
|
"minion": {
|
|
"module_|-simple-ping_|-test.ping_|-run": {
|
|
"__id__": "simple-ping",
|
|
"__run_num__": 0,
|
|
"__sls__": "simple-ping",
|
|
"changes": {"ret": True},
|
|
"comment": "Module function test.ping executed",
|
|
"duration": 56.179,
|
|
"name": "test.ping",
|
|
"result": True,
|
|
"start_time": "15:35:31.282099",
|
|
}
|
|
},
|
|
"sub_minion": {
|
|
"module_|-simple-ping_|-test.ping_|-run": {
|
|
"__id__": "simple-ping",
|
|
"__run_num__": 0,
|
|
"__sls__": "simple-ping",
|
|
"changes": {"ret": True},
|
|
"comment": "Module function test.ping executed",
|
|
"duration": 54.103,
|
|
"name": "test.ping",
|
|
"result": True,
|
|
"start_time": "15:35:31.005606",
|
|
}
|
|
},
|
|
},
|
|
},
|
|
"comment": (
|
|
"States ran successfully. Updating sub_minion, minion."
|
|
),
|
|
"duration": 1638.047,
|
|
"name": "call_sleep_state",
|
|
"result": True,
|
|
"start_time": "15:35:29.762657",
|
|
},
|
|
"salt_|-cmd_run_example_|-cmd.run_|-function": {
|
|
"__id__": "cmd_run_example",
|
|
"__jid__": "20200411195112288850",
|
|
"__run_num__": 1,
|
|
"__sls__": "orch.simple",
|
|
"changes": {
|
|
"out": "highstate",
|
|
"ret": {"minion": "file1\nfile2\nfile3"},
|
|
},
|
|
"comment": (
|
|
"Function ran successfully. Function cmd.run ran on minion."
|
|
),
|
|
"duration": 412.397,
|
|
"name": "cmd.run",
|
|
"result": True,
|
|
"start_time": "21:51:12.185868",
|
|
},
|
|
}
|
|
},
|
|
"outputter": "highstate",
|
|
"retcode": 0,
|
|
}
|
|
|
|
actual_output = highstate.output(data)
|
|
assert "Succeeded: 1 (changed=1)" in actual_output
|
|
assert "Failed: 0" in actual_output
|
|
assert "Success %: 100.0" in actual_output
|
|
assert "Failure %: 0.0" in actual_output
|
|
assert "Total states run: 1" in actual_output
|
|
assert " file2" in actual_output
|
|
|
|
|
|
def test__compress_ids():
|
|
"""
|
|
Tests for expected data return for _compress_ids
|
|
and proper formatting using the state_compress_ids option
|
|
"""
|
|
# Stop using OrderedDict once we drop Py3.5 support
|
|
data = OrderedDict()
|
|
# raw data entering the outputter
|
|
data["local"] = {
|
|
"cmd_|-mix-matched results_|-/bin/false_|-run": {
|
|
"__id__": "mix-matched results",
|
|
"__run_num__": 7,
|
|
"__sls__": "compress_test",
|
|
"changes": {"pid": 6554, "retcode": 1, "stderr": "", "stdout": ""},
|
|
"comment": "Command " '"/bin/false" ' "run",
|
|
"duration": 8.57,
|
|
"name": "/bin/false",
|
|
"result": False,
|
|
"start_time": "15:38:22.666578",
|
|
},
|
|
"cmd_|-mix-matched results_|-/bin/true_|-run": {
|
|
"__id__": "mix-matched results",
|
|
"__run_num__": 6,
|
|
"__sls__": "compress_test",
|
|
"changes": {"pid": 6553, "retcode": 0, "stderr": "", "stdout": ""},
|
|
"comment": "Command " '"/bin/true" ' "run",
|
|
"duration": 7.728,
|
|
"name": "/bin/true",
|
|
"result": True,
|
|
"start_time": "15:38:22.658452",
|
|
},
|
|
"cmd_|-mix-matched results_|-false_|-run": {
|
|
"__id__": "mix-matched results",
|
|
"__run_num__": 5,
|
|
"__sls__": "compress_test",
|
|
"changes": {"pid": 6552, "retcode": 1, "stderr": "", "stdout": ""},
|
|
"comment": "Command " '"false" run',
|
|
"duration": 7.832,
|
|
"name": "false",
|
|
"result": False,
|
|
"start_time": "15:38:22.650225",
|
|
},
|
|
"cmd_|-mix-matched results_|-true_|-run": {
|
|
"__id__": "mix-matched results",
|
|
"__run_num__": 4,
|
|
"__sls__": "compress_test",
|
|
"changes": {"pid": 6551, "retcode": 0, "stderr": "", "stdout": ""},
|
|
"comment": "Command " '"true" run',
|
|
"duration": 8.538,
|
|
"name": "true",
|
|
"result": True,
|
|
"start_time": "15:38:22.641293",
|
|
},
|
|
"file_|-one clean one changes_|-/tmp/changes_|-managed": {
|
|
"__id__": "one clean one changes",
|
|
"__run_num__": 13,
|
|
"__sls__": "compress_test",
|
|
"changes": {"diff": "New file"},
|
|
"comment": "File /tmp/changes updated",
|
|
"duration": 3.17,
|
|
"name": "/tmp/changes",
|
|
"result": True,
|
|
"start_time": "15:38:22.703770",
|
|
},
|
|
"file_|-one clean one changes_|-/tmp/clean_|-managed": {
|
|
"__id__": "one clean one changes",
|
|
"__run_num__": 12,
|
|
"__sls__": "compress_test",
|
|
"changes": {},
|
|
"comment": "File /tmp/clean is in the correct state",
|
|
"duration": 20.123,
|
|
"name": "/tmp/clean",
|
|
"result": True,
|
|
"start_time": "15:38:22.683450",
|
|
},
|
|
"test_|-succeed clean_|-bar_|-succeed_without_changes": {
|
|
"__id__": "succeed clean",
|
|
"__run_num__": 11,
|
|
"__sls__": "compress_test",
|
|
"changes": {},
|
|
"comment": "Success!",
|
|
"duration": 0.759,
|
|
"name": "bar",
|
|
"result": True,
|
|
"start_time": "15:38:22.678512",
|
|
},
|
|
"test_|-succeed clean_|-foo_|-succeed_without_changes": {
|
|
"__id__": "succeed clean",
|
|
"__run_num__": 10,
|
|
"__sls__": "compress_test",
|
|
"changes": {},
|
|
"comment": "Success!",
|
|
"duration": 0.676,
|
|
"name": "foo",
|
|
"result": True,
|
|
"start_time": "15:38:22.677678",
|
|
},
|
|
"test_|-succeed clean_|-hello_|-succeed_without_changes": {
|
|
"__id__": "succeed clean",
|
|
"__run_num__": 8,
|
|
"__sls__": "compress_test",
|
|
"changes": {},
|
|
"comment": "Success!",
|
|
"duration": 1.071,
|
|
"name": "hello",
|
|
"result": True,
|
|
"start_time": "15:38:22.675588",
|
|
},
|
|
"test_|-succeed clean_|-world_|-succeed_without_changes": {
|
|
"__id__": "succeed clean",
|
|
"__run_num__": 9,
|
|
"__sls__": "compress_test",
|
|
"changes": {},
|
|
"comment": "Success!",
|
|
"duration": 0.693,
|
|
"name": "world",
|
|
"result": True,
|
|
"start_time": "15:38:22.676826",
|
|
},
|
|
"test_|-succeed with changes_|-bar_|-succeed_with_changes": {
|
|
"__id__": "succeed with changes",
|
|
"__run_num__": 3,
|
|
"__sls__": "compress_test",
|
|
"changes": {
|
|
"testing": {
|
|
"new": "Something pretended to change",
|
|
"old": "Unchanged",
|
|
}
|
|
},
|
|
"comment": "Success!",
|
|
"duration": 0.829,
|
|
"name": "bar",
|
|
"result": True,
|
|
"start_time": "15:38:22.639625",
|
|
},
|
|
"test_|-succeed with changes_|-foo_|-succeed_with_changes": {
|
|
"__id__": "succeed with changes",
|
|
"__run_num__": 2,
|
|
"__sls__": "compress_test",
|
|
"changes": {
|
|
"testing": {
|
|
"new": "Something pretended to change",
|
|
"old": "Unchanged",
|
|
}
|
|
},
|
|
"comment": "Success!",
|
|
"duration": 0.739,
|
|
"name": "foo",
|
|
"result": True,
|
|
"start_time": "15:38:22.638724",
|
|
},
|
|
"test_|-succeed with changes_|-hello_|-succeed_with_changes": {
|
|
"__id__": "succeed with changes",
|
|
"__run_num__": 0,
|
|
"__sls__": "compress_test",
|
|
"changes": {
|
|
"testing": {
|
|
"new": "Something pretended to change",
|
|
"old": "Unchanged",
|
|
}
|
|
},
|
|
"comment": "Success!",
|
|
"duration": 0.812,
|
|
"name": "hello",
|
|
"result": True,
|
|
"start_time": "15:38:22.636883",
|
|
},
|
|
"test_|-succeed with changes_|-world_|-succeed_with_changes": {
|
|
"__id__": "succeed with changes",
|
|
"__run_num__": 1,
|
|
"__sls__": "compress_test",
|
|
"changes": {
|
|
"testing": {
|
|
"new": "Something pretended to change",
|
|
"old": "Unchanged",
|
|
}
|
|
},
|
|
"comment": "Success!",
|
|
"duration": 0.694,
|
|
"name": "world",
|
|
"result": True,
|
|
"start_time": "15:38:22.637872",
|
|
},
|
|
"test_|-single clean_|-single_|-succeed_without_changes": {
|
|
"__id__": "single clean",
|
|
"__run_num__": 14,
|
|
"__sls__": "compress_test",
|
|
"changes": {},
|
|
"comment": "Success!",
|
|
"duration": 0.693,
|
|
"name": "single",
|
|
"result": True,
|
|
"start_time": "15:38:22.676827",
|
|
},
|
|
}
|
|
# Stop using OrderedDict once we drop Py3.5 support
|
|
expected_output = OrderedDict()
|
|
# expected compressed raw data for outputter
|
|
expected_output["local"] = {
|
|
"cmd_|-mix-matched results (2)_|-state_compressed_compress_test_mix-matched results_False_|-run": {
|
|
"__id__": "mix-matched results",
|
|
"__run_num__": 5,
|
|
"__sls__": "compress_test",
|
|
"changes": {
|
|
"compressed changes": {
|
|
"/bin/false": {
|
|
"pid": 6554,
|
|
"retcode": 1,
|
|
"stderr": "",
|
|
"stdout": "",
|
|
},
|
|
"false": {
|
|
"pid": 6552,
|
|
"retcode": 1,
|
|
"stderr": "",
|
|
"stdout": "",
|
|
},
|
|
}
|
|
},
|
|
"comment": "Command " '"/bin/false" ' "run",
|
|
"duration": 16.402,
|
|
"name": "/bin/false",
|
|
"result": False,
|
|
"start_time": "15:38:22.650225",
|
|
},
|
|
"cmd_|-mix-matched results (2)_|-state_compressed_compress_test_mix-matched results_True_|-run": {
|
|
"__id__": "mix-matched results",
|
|
"__run_num__": 4,
|
|
"__sls__": "compress_test",
|
|
"changes": {
|
|
"compressed changes": {
|
|
"/bin/true": {
|
|
"pid": 6553,
|
|
"retcode": 0,
|
|
"stderr": "",
|
|
"stdout": "",
|
|
},
|
|
"true": {"pid": 6551, "retcode": 0, "stderr": "", "stdout": ""},
|
|
}
|
|
},
|
|
"comment": "Command " '"/bin/true" ' "run",
|
|
"duration": 16.266,
|
|
"name": "/bin/true",
|
|
"result": True,
|
|
"start_time": "15:38:22.641293",
|
|
},
|
|
"file_|-one clean one changes (2)_|-state_compressed_compress_test_one clean one changes_True_|-managed": {
|
|
"__id__": "one clean one changes",
|
|
"__run_num__": 12,
|
|
"__sls__": "compress_test",
|
|
"changes": {"diff": "New file"},
|
|
"comment": "File /tmp/changes updated",
|
|
"duration": 23.293,
|
|
"name": "/tmp/changes",
|
|
"result": True,
|
|
"start_time": "15:38:22.683450",
|
|
},
|
|
"test_|-succeed clean (4)_|-state_compressed_compress_test_succeed clean_True_|-succeed_without_changes": {
|
|
"__id__": "succeed clean",
|
|
"__run_num__": 8,
|
|
"__sls__": "compress_test",
|
|
"changes": {},
|
|
"comment": "Success!",
|
|
"duration": 3.199,
|
|
"name": "bar",
|
|
"result": True,
|
|
"start_time": "15:38:22.675588",
|
|
},
|
|
"test_|-succeed with changes (4)_|-state_compressed_compress_test_succeed with changes_True_|-succeed_with_changes": {
|
|
"__id__": "succeed with changes",
|
|
"__run_num__": 0,
|
|
"__sls__": "compress_test",
|
|
"changes": {
|
|
"compressed changes": {
|
|
"bar": {
|
|
"testing": {
|
|
"new": "Something pretended to change",
|
|
"old": "Unchanged",
|
|
}
|
|
},
|
|
"foo": {
|
|
"testing": {
|
|
"new": "Something pretended to change",
|
|
"old": "Unchanged",
|
|
}
|
|
},
|
|
"hello": {
|
|
"testing": {
|
|
"new": "Something pretended to change",
|
|
"old": "Unchanged",
|
|
}
|
|
},
|
|
"world": {
|
|
"testing": {
|
|
"new": "Something pretended to change",
|
|
"old": "Unchanged",
|
|
}
|
|
},
|
|
}
|
|
},
|
|
"comment": "Success!",
|
|
"duration": 3.074,
|
|
"name": "bar",
|
|
"result": True,
|
|
"start_time": "15:38:22.636883",
|
|
},
|
|
"test_|-single clean_|-single_|-succeed_without_changes": {
|
|
"__id__": "single clean",
|
|
"__run_num__": 14,
|
|
"__sls__": "compress_test",
|
|
"changes": {},
|
|
"comment": "Success!",
|
|
"duration": 0.693,
|
|
"name": "single",
|
|
"result": True,
|
|
"start_time": "15:38:22.676827",
|
|
},
|
|
}
|
|
actual_output = highstate._compress_ids(data)
|
|
|
|
# return properly compressed data
|
|
assert actual_output == expected_output
|
|
|
|
# check output text for formatting
|
|
opts = copy.deepcopy(highstate.__opts__)
|
|
opts["state_compress_ids"] = True
|
|
with patch("salt.output.highstate.__opts__", opts, create=True):
|
|
actual_output = highstate.output(data)
|
|
assert " ID: succeed with changes (4)" in actual_output
|
|
assert (
|
|
" Name: state_compressed_compress_test_succeed with changes_True"
|
|
in actual_output
|
|
)
|
|
assert " compressed changes:" in actual_output
|
|
assert " ID: mix-matched results (2)" in actual_output
|
|
assert (
|
|
" Name: state_compressed_compress_test_mix-matched results_True"
|
|
in actual_output
|
|
)
|
|
assert (
|
|
" Name: state_compressed_compress_test_mix-matched results_False"
|
|
in actual_output
|
|
)
|
|
assert " ID: succeed clean (4)" in actual_output
|
|
assert (
|
|
" Name: state_compressed_compress_test_succeed clean_True"
|
|
in actual_output
|
|
)
|
|
assert " ID: one clean one changes (2)" in actual_output
|
|
assert (
|
|
" Name: state_compressed_compress_test_one clean one changes_True"
|
|
in actual_output
|
|
)
|
|
assert " diff:" in actual_output
|
|
assert "Succeeded: 13 (changed=9)" in actual_output
|
|
assert "Failed: 2" in actual_output
|
|
assert "Success %: 86.67" in actual_output
|
|
assert "Failure %: 13.33" in actual_output
|
|
assert "Total states run: 15" in actual_output
|
|
|
|
# pop out a __run_num__ to break the data
|
|
data["local"]["cmd_|-mix-matched results_|-/bin/false_|-run"].pop("__run_num__")
|
|
actual_output = highstate._compress_ids(data)
|
|
|
|
# expecting return of original data to let the outputter figure it out
|
|
assert actual_output == data
|
|
|
|
|
|
def test__compress_ids_not_dict():
|
|
"""
|
|
Simple test for returning original malformed data
|
|
to let the outputter figure it out.
|
|
"""
|
|
data = ["malformed"]
|
|
actual_output = highstate._compress_ids(data)
|
|
assert actual_output == data
|