From e1000011ae4819152961564ecc6423d0bc1e0150 Mon Sep 17 00:00:00 2001 From: "Gareth J. Greenaway" Date: Mon, 16 Oct 2023 08:14:46 -0700 Subject: [PATCH 01/11] Additional test cases for slsutil. Reworking some of the slsutil to ensure test coverage is easier. --- salt/modules/slsutil.py | 5 +- tests/pytests/unit/modules/test_slsutil.py | 177 ++++++++++++++++++++- 2 files changed, 179 insertions(+), 3 deletions(-) diff --git a/salt/modules/slsutil.py b/salt/modules/slsutil.py index 4345bc02e14..fe7ba15f336 100644 --- a/salt/modules/slsutil.py +++ b/salt/modules/slsutil.py @@ -163,13 +163,16 @@ def renderer(path=None, string=None, default_renderer="jinja|yaml", **kwargs): if not path and not string: raise salt.exceptions.SaltInvocationError("Must pass either path or string") + if path and string: + raise salt.exceptions.SaltInvocationError("Must not pass both path and string") + renderers = salt.loader.render(__opts__, __salt__) if path: path_or_string = __salt__["cp.get_url"]( path, saltenv=kwargs.get("saltenv", "base") ) - elif string: + if string: path_or_string = ":string:" kwargs["input_data"] = string diff --git a/tests/pytests/unit/modules/test_slsutil.py b/tests/pytests/unit/modules/test_slsutil.py index 49651d55c27..46eb221552a 100644 --- a/tests/pytests/unit/modules/test_slsutil.py +++ b/tests/pytests/unit/modules/test_slsutil.py @@ -1,18 +1,20 @@ import logging +from io import StringIO import pytest import salt.exceptions import salt.modules.slsutil as slsutil -from tests.support.mock import MagicMock +from tests.support.mock import MagicMock, patch log = logging.getLogger(__name__) @pytest.fixture -def configure_loader_modules(master_dirs, master_files): +def configure_loader_modules(master_dirs, master_files, minion_opts): return { slsutil: { + "__opts__": minion_opts, "__salt__": { "cp.list_master": MagicMock(return_value=master_files), "cp.list_master_dirs": MagicMock(return_value=master_dirs), @@ -47,6 +49,21 @@ def test_banner(): check_banner(commentchar="//", borderchar="-") check_banner(title="title here", text="text here") check_banner(commentchar=" *") + check_banner(commentchar=" *", newline=False) + + # Test when width result in a raised exception + with pytest.raises(salt.exceptions.ArgumentValueError): + slsutil.banner(width=4) + + ret = slsutil.banner( + title="title here", text="text here", blockstart="/*", blockend="*/" + ) + lines = ret.splitlines() + # test blockstart + assert lines[0] == "/*" + + # test blockend + assert lines[-1] == "*/" def check_banner( @@ -125,3 +142,159 @@ def test_findup(): with pytest.raises(salt.exceptions.CommandExecutionError): slsutil.findup("red", "default.conf") + + with pytest.raises(salt.exceptions.SaltInvocationError): + with patch.object(slsutil, "path_exists", return_value=False): + slsutil.findup("red", "default.conf") + + with pytest.raises(salt.exceptions.SaltInvocationError): + slsutil.findup("red", {"file": "default.conf"}) + + +def test_update(): + """ + Test update function + """ + + ret = slsutil.update({"foo": "Foo"}, {"bar": "Bar"}) + assert ret == {"foo": "Foo", "bar": "Bar"} + + ret = slsutil.update({"foo": "Foo"}, {"foo": "Bar"}, merge_lists=False) + assert ret == {"foo": "Bar"} + + +def test_merge(): + """ + Test merge function + """ + + ret = slsutil.merge({"foo": "Foo"}, {"bar": "Bar"}, strategy="smart") + assert ret == {"foo": "Foo", "bar": "Bar"} + + ret = slsutil.merge({"foo": "Foo"}, {"foo": "Bar"}, strategy="aggregate") + assert ret == {"foo": "Bar"} + + ret = slsutil.merge({"foo": "Foo"}, {"foo": "Bar"}, strategy="list") + assert ret == {"foo": ["Foo", "Bar"]} + + ret = slsutil.merge({"foo": "Foo"}, {"foo": "Bar"}, strategy="overwrite") + assert ret == {"foo": "Bar"} + + ret = slsutil.merge( + {"foo": {"Foo": "Bar"}}, {"foo": {"Foo": "Baz"}}, strategy="recurse" + ) + assert ret == {"foo": {"Foo": "Baz"}} + + +def test_merge_all(): + """ + Test merge_all function + """ + + ret = slsutil.merge_all([{"foo": "Foo"}, {"bar": "Bar"}], strategy="smart") + assert ret == {"foo": "Foo", "bar": "Bar"} + + ret = slsutil.merge_all([{"foo": "Foo"}, {"foo": "Bar"}], strategy="aggregate") + assert ret == {"foo": "Bar"} + + ret = slsutil.merge_all([{"foo": "Foo"}, {"foo": "Bar"}], strategy="overwrite") + assert ret == {"foo": "Bar"} + + ret = slsutil.merge_all( + [{"foo": {"Foo": "Bar"}}, {"foo": {"Foo": "Baz"}}], strategy="recurse" + ) + assert ret == {"foo": {"Foo": "Baz"}} + + +def test_renderer(): + """ + Test renderer function + """ + with patch.dict( + slsutil.__utils__, {"stringio.is_readable": MagicMock(return_value=False)} + ): + ret = slsutil.renderer(string="Hello, {{ name }}.", name="world") + assert ret == "Hello, world." + + with pytest.raises(salt.exceptions.SaltInvocationError) as exc: + slsutil.renderer() + assert str(exc.value) == "Must pass path or string." + + with pytest.raises(salt.exceptions.SaltInvocationError) as exc: + slsutil.renderer(path="/path/to/file", string="Hello world") + assert str(exc.value) == "Must not pass both path and string." + + with patch.dict( + slsutil.__salt__, {"cp.get_url": MagicMock(return_value="/path/to/file")} + ): + with patch.dict( + slsutil.__utils__, {"stringio.is_readable": MagicMock(return_value=True)} + ): + rendered_file = "Hello, world." + with patch( + "salt.template.compile_template", + MagicMock(return_value=StringIO(rendered_file)), + ): + ret = slsutil.renderer(path="/path/to/file") + assert ret == "Hello, world." + + +def test_serialize(): + """ + Test serialize function + """ + ret = slsutil.serialize("json", obj={"foo": "Foo!"}) + assert ret == '{"foo": "Foo!"}' + + +def test_deserialize(): + """ + Test serialize function + """ + ret = slsutil.deserialize("json", '{"foo": "Foo!"}') + assert ret == {"foo": "Foo!"} + + +def dummy_function(args=None, kwargs=None): + return True + + +def test__set_context(): + """ + Test _set_context + """ + with patch.dict(slsutil.__context__, {}): + + slsutil._set_context( + ["level_one", "level_two", "level_three"], dummy_function, force=True + ) + assert slsutil.__context__ == { + "level_one": {"level_two": {"level_three": True}} + } + + with patch.dict(slsutil.__context__, {}): + + slsutil._set_context( + ["level_one", "level_two", "level_three"], + dummy_function, + fun_kwargs={"key_one": "arg_one"}, + force=True, + ) + assert slsutil.__context__ == { + "level_one": {"level_two": {"level_three": True}} + } + + +def test__get_serializer_fn(): + """ + Test _set_context + """ + # Invalid serializer + with pytest.raises(salt.exceptions.CommandExecutionError) as exc: + slsutil._get_serialize_fn("bad_yaml", "badfunc") + assert str(exc.value) == "Serializer 'bad_yaml' not found." + + # Invalid serializer function + with pytest.raises(salt.exceptions.CommandExecutionError) as exc: + slsutil._get_serialize_fn("yaml", "foobar") + assert str(exc.value) == "Serializer 'yaml' does not implement foobar." From fd4e3a225a444be5e063f3037f15872918140e90 Mon Sep 17 00:00:00 2001 From: Felippe Burk Date: Fri, 15 Dec 2023 11:13:20 -0700 Subject: [PATCH 02/11] update photon paths to use their $releasever string string which includes .0 --- tests/pytests/pkg/download/test_pkg_download.py | 3 +++ tools/pkg/repo/create.py | 3 +++ 2 files changed, 6 insertions(+) diff --git a/tests/pytests/pkg/download/test_pkg_download.py b/tests/pytests/pkg/download/test_pkg_download.py index 0fa9089e77d..dce3880ed8b 100644 --- a/tests/pytests/pkg/download/test_pkg_download.py +++ b/tests/pytests/pkg/download/test_pkg_download.py @@ -256,6 +256,9 @@ def setup_redhat_family( ): arch = os.environ.get("SALT_REPO_ARCH") or "x86_64" + if os_name == "photon": + os_version = f"{os_version}.0" + if repo_subpath == "minor": repo_url_base = ( f"{root_url}/{os_name}/{os_version}/{arch}/{repo_subpath}/{salt_release}" diff --git a/tools/pkg/repo/create.py b/tools/pkg/repo/create.py index d9b8fb0a97d..3e94575639e 100644 --- a/tools/pkg/repo/create.py +++ b/tools/pkg/repo/create.py @@ -380,6 +380,9 @@ def rpm( assert incoming is not None assert repo_path is not None assert key_id is not None + + if distro == "photon": + distro_version = f"{distro_version}.0" display_name = f"{distro.capitalize()} {distro_version}" if distro_version not in _rpm_distro_info[distro]: ctx.error(f"Support for {display_name} is missing.") From 99c6260b8f54c1416f9775980f0d459708ae88e5 Mon Sep 17 00:00:00 2001 From: Felippe Burk Date: Fri, 15 Dec 2023 13:14:23 -0700 Subject: [PATCH 03/11] Revert "update photon paths to use their $releasever string string which includes .0" This reverts commit fd4e3a225a444be5e063f3037f15872918140e90. --- tests/pytests/pkg/download/test_pkg_download.py | 3 --- tools/pkg/repo/create.py | 3 --- 2 files changed, 6 deletions(-) diff --git a/tests/pytests/pkg/download/test_pkg_download.py b/tests/pytests/pkg/download/test_pkg_download.py index dce3880ed8b..0fa9089e77d 100644 --- a/tests/pytests/pkg/download/test_pkg_download.py +++ b/tests/pytests/pkg/download/test_pkg_download.py @@ -256,9 +256,6 @@ def setup_redhat_family( ): arch = os.environ.get("SALT_REPO_ARCH") or "x86_64" - if os_name == "photon": - os_version = f"{os_version}.0" - if repo_subpath == "minor": repo_url_base = ( f"{root_url}/{os_name}/{os_version}/{arch}/{repo_subpath}/{salt_release}" diff --git a/tools/pkg/repo/create.py b/tools/pkg/repo/create.py index 3e94575639e..d9b8fb0a97d 100644 --- a/tools/pkg/repo/create.py +++ b/tools/pkg/repo/create.py @@ -380,9 +380,6 @@ def rpm( assert incoming is not None assert repo_path is not None assert key_id is not None - - if distro == "photon": - distro_version = f"{distro_version}.0" display_name = f"{distro.capitalize()} {distro_version}" if distro_version not in _rpm_distro_info[distro]: ctx.error(f"Support for {display_name} is missing.") From 55042e396dd3a3cb2a91b01cb4d91ad17e3dce9d Mon Sep 17 00:00:00 2001 From: Felippe Burk Date: Fri, 15 Dec 2023 13:17:54 -0700 Subject: [PATCH 04/11] update photon paths to use their $releasever string --- tests/pytests/pkg/download/test_pkg_download.py | 3 +++ tools/pkg/repo/create.py | 3 +++ 2 files changed, 6 insertions(+) diff --git a/tests/pytests/pkg/download/test_pkg_download.py b/tests/pytests/pkg/download/test_pkg_download.py index 0fa9089e77d..dce3880ed8b 100644 --- a/tests/pytests/pkg/download/test_pkg_download.py +++ b/tests/pytests/pkg/download/test_pkg_download.py @@ -256,6 +256,9 @@ def setup_redhat_family( ): arch = os.environ.get("SALT_REPO_ARCH") or "x86_64" + if os_name == "photon": + os_version = f"{os_version}.0" + if repo_subpath == "minor": repo_url_base = ( f"{root_url}/{os_name}/{os_version}/{arch}/{repo_subpath}/{salt_release}" diff --git a/tools/pkg/repo/create.py b/tools/pkg/repo/create.py index d9b8fb0a97d..3e94575639e 100644 --- a/tools/pkg/repo/create.py +++ b/tools/pkg/repo/create.py @@ -380,6 +380,9 @@ def rpm( assert incoming is not None assert repo_path is not None assert key_id is not None + + if distro == "photon": + distro_version = f"{distro_version}.0" display_name = f"{distro.capitalize()} {distro_version}" if distro_version not in _rpm_distro_info[distro]: ctx.error(f"Support for {display_name} is missing.") From ffa94783045da7ac04d79d9c9a12cc7e495ac369 Mon Sep 17 00:00:00 2001 From: "Daniel A. Wozniak" Date: Thu, 14 Dec 2023 23:47:14 -0700 Subject: [PATCH 05/11] Make pillar timeout test less flaky --- tests/pytests/integration/minion/test_return_retries.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/pytests/integration/minion/test_return_retries.py b/tests/pytests/integration/minion/test_return_retries.py index 8a226d26cd4..24be4c39695 100644 --- a/tests/pytests/integration/minion/test_return_retries.py +++ b/tests/pytests/integration/minion/test_return_retries.py @@ -55,7 +55,7 @@ def test_publish_retry(salt_master, salt_minion_retry, salt_cli, salt_run_cli): @pytest.mark.slow_test def test_pillar_timeout(salt_master_factory): cmd = """ - python -c "import time; time.sleep(2.5); print('{\\"foo\\": \\"bar\\"}');\" + python -c "import time; time.sleep(3.0); print('{\\"foo\\": \\"bar\\"}');\" """.strip() master_overrides = { "ext_pillar": [ From 0e282e651eb3a5b46fcae471947bfcd0e3754cbb Mon Sep 17 00:00:00 2001 From: Frode Gundersen Date: Thu, 16 Feb 2023 20:15:07 +0000 Subject: [PATCH 06/11] migrate unit_states_test_grains to pytest --- tests/pytests/unit/states/test_grains.py | 876 ++++++++++++++++++++++ tests/unit/states/test_grains.py | 897 ----------------------- 2 files changed, 876 insertions(+), 897 deletions(-) create mode 100644 tests/pytests/unit/states/test_grains.py delete mode 100644 tests/unit/states/test_grains.py diff --git a/tests/pytests/unit/states/test_grains.py b/tests/pytests/unit/states/test_grains.py new file mode 100644 index 00000000000..43f2afd9df5 --- /dev/null +++ b/tests/pytests/unit/states/test_grains.py @@ -0,0 +1,876 @@ +""" +unit tests for the grains state +""" + + +import contextlib +import os + +import pytest + +import salt.modules.grains as grainsmod +import salt.states.grains as grains +import salt.utils.files +import salt.utils.stringutils +import salt.utils.yaml +from tests.support.mock import MagicMock, patch +from tests.support.paths import SALT_CODE_DIR + + +@pytest.fixture +def configure_loader_modules(): + grains_test_dir = "__salt_test_state_grains" + if not os.path.exists(os.path.join(SALT_CODE_DIR, grains_test_dir)): + os.makedirs(os.path.join(SALT_CODE_DIR, grains_test_dir)) + loader_globals = { + "__opts__": { + "test": False, + "conf_file": os.path.join(SALT_CODE_DIR, grains_test_dir, "minion"), + "cachedir": os.path.join(SALT_CODE_DIR, grains_test_dir), + "local": True, + }, + "__salt__": { + "cmd.run_all": MagicMock( + return_value={"pid": 5, "retcode": 0, "stderr": "", "stdout": ""} + ), + "grains.get": grainsmod.get, + "grains.set": grainsmod.set, + "grains.setval": grainsmod.setval, + "grains.delval": grainsmod.delval, + "grains.append": grainsmod.append, + "grains.remove": grainsmod.remove, + "saltutil.sync_grains": MagicMock(), + }, + } + return {grains: loader_globals, grainsmod: loader_globals} + + +def assertGrainFileContent(grains_string): + if os.path.isdir(grains.__opts__["conf_file"]): + grains_file = os.path.join(grains.__opts__["conf_file"], "grains") + else: + grains_file = os.path.join( + os.path.dirname(grains.__opts__["conf_file"]), "grains" + ) + with salt.utils.files.fopen(grains_file, "r") as grf: + grains_data = salt.utils.stringutils.to_unicode(grf.read()) + assert grains_string == grains_data + + +@contextlib.contextmanager +def setGrains(grains_data): + with patch.dict(grains.__grains__, grains_data): + with patch.dict(grainsmod.__grains__, grains_data): + if os.path.isdir(grains.__opts__["conf_file"]): + grains_file = os.path.join(grains.__opts__["conf_file"], "grains") + else: + grains_file = os.path.join( + os.path.dirname(grains.__opts__["conf_file"]), "grains" + ) + with salt.utils.files.fopen(grains_file, "w+") as grf: + salt.utils.yaml.safe_dump(grains_data, grf, default_flow_style=False) + yield + + +# 'exists' function tests: 2 + + +def test_exists_missing(): + with setGrains({"a": "aval"}): + ret = grains.exists(name="foo") + assert ret["result"] is False + assert ret["comment"] == "Grain does not exist" + assert ret["changes"] == {} + + +def test_exists_found(): + with setGrains({"a": "aval", "foo": "bar"}): + # Grain already set + ret = grains.exists(name="foo") + assert ret["result"] is True + assert ret["comment"] == "Grain exists" + assert ret["changes"] == {} + + # 'make_hashable' function tests: 1 + + +def test_make_hashable(): + with setGrains({"cmplx_lst_grain": [{"a": "aval"}, {"foo": "bar"}]}): + hashable_list = {"cmplx_lst_grain": [{"a": "aval"}, {"foo": "bar"}]} + assert ( + grains.make_hashable(grains.__grains__).issubset( + grains.make_hashable(hashable_list) + ) + is True + ) + + # 'present' function tests: 12 + + +def test_present_add(): + # Set a non existing grain + with setGrains({"a": "aval"}): + ret = grains.present(name="foo", value="bar") + assert ret["result"] is True + assert ret["changes"] == {"foo": "bar"} + assert grains.__grains__ == {"a": "aval", "foo": "bar"} + assertGrainFileContent("a: aval\nfoo: bar\n") + + # Set a non existing nested grain + with setGrains({"a": "aval"}): + ret = grains.present(name="foo:is:nested", value="bar") + assert ret["result"] is True + assert ret["changes"] == {"foo": {"is": {"nested": "bar"}}} + assert grains.__grains__ == {"a": "aval", "foo": {"is": {"nested": "bar"}}} + assertGrainFileContent("a: aval\nfoo:\n is:\n nested: bar\n") + + # Set a non existing nested dict grain + with setGrains({"a": "aval"}): + ret = grains.present(name="foo:is:nested", value={"bar": "is a dict"}) + assert ret["result"] is True + assert ret["changes"] == {"foo": {"is": {"nested": {"bar": "is a dict"}}}} + assert grains.__grains__ == { + "a": "aval", + "foo": {"is": {"nested": {"bar": "is a dict"}}}, + } + assertGrainFileContent( + "a: aval\n" + + "foo:\n" + + " is:\n" + + " nested:\n" + + " bar: is a dict\n" + ) + + +def test_present_add_key_to_existing(): + with setGrains({"a": "aval", "foo": {"k1": "v1"}}): + # Fails setting a grain to a dict + ret = grains.present(name="foo:k2", value="v2") + assert ret["result"] is True + assert ret["comment"] == "Set grain foo:k2 to v2" + assert ret["changes"] == {"foo": {"k2": "v2", "k1": "v1"}} + assert grains.__grains__ == {"a": "aval", "foo": {"k1": "v1", "k2": "v2"}} + assertGrainFileContent("a: aval\n" + "foo:\n" + " k1: v1\n" + " k2: v2\n") + + +def test_present_already_set(): + with setGrains({"a": "aval", "foo": "bar"}): + # Grain already set + ret = grains.present(name="foo", value="bar") + assert ret["result"] is True + assert ret["comment"] == "Grain is already set" + assert ret["changes"] == {} + assert grains.__grains__ == {"a": "aval", "foo": "bar"} + + with setGrains({"a": "aval", "foo": {"is": {"nested": "bar"}}}): + # Nested grain already set + ret = grains.present(name="foo:is:nested", value="bar") + assert ret["result"] is True + assert ret["comment"] == "Grain is already set" + assert ret["changes"] == {} + assert grains.__grains__ == {"a": "aval", "foo": {"is": {"nested": "bar"}}} + + with setGrains({"a": "aval", "foo": {"is": {"nested": "bar"}}}): + # Nested dict grain already set + ret = grains.present(name="foo:is", value={"nested": "bar"}) + assert ret["result"] is True + assert ret["comment"] == "Grain is already set" + assert ret["changes"] == {} + assert grains.__grains__ == {"a": "aval", "foo": {"is": {"nested": "bar"}}} + + +def test_present_overwrite(): + with setGrains({"a": "aval", "foo": "bar"}): + # Overwrite an existing grain + ret = grains.present(name="foo", value="newbar") + assert ret["result"] is True + assert ret["changes"] == {"foo": "newbar"} + assert grains.__grains__ == {"a": "aval", "foo": "newbar"} + assertGrainFileContent("a: aval\n" + "foo: newbar\n") + + with setGrains({"a": "aval", "foo": "bar"}): + # Clear a grain (set to None) + ret = grains.present(name="foo", value=None) + assert ret["result"] is True + assert ret["changes"] == {"foo": None} + assert grains.__grains__ == {"a": "aval", "foo": None} + assertGrainFileContent("a: aval\n" + "foo: null\n") + + with setGrains({"a": "aval", "foo": {"is": {"nested": "bar"}}}): + # Overwrite an existing nested grain + ret = grains.present(name="foo:is:nested", value="newbar") + assert ret["result"] is True + assert ret["changes"] == {"foo": {"is": {"nested": "newbar"}}} + assert grains.__grains__ == {"a": "aval", "foo": {"is": {"nested": "newbar"}}} + assertGrainFileContent( + "a: aval\n" + "foo:\n" + " is:\n" + " nested: newbar\n" + ) + + with setGrains({"a": "aval", "foo": {"is": {"nested": "bar"}}}): + # Clear a nested grain (set to None) + ret = grains.present(name="foo:is:nested", value=None) + assert ret["result"] is True + assert ret["changes"] == {"foo": {"is": {"nested": None}}} + assert grains.__grains__ == {"a": "aval", "foo": {"is": {"nested": None}}} + assertGrainFileContent( + "a: aval\n" + "foo:\n" + " is:\n" + " nested: null\n" + ) + + +def test_present_fail_overwrite(): + with setGrains({"a": "aval", "foo": {"is": {"nested": "val"}}}): + # Overwrite an existing grain + ret = grains.present(name="foo:is", value="newbar") + assert ret["result"] is False + assert ret["changes"] == {} + assert ( + ret["comment"] + == "The key 'foo:is' exists but is a dict or a list. Use 'force=True' to overwrite." + ) + assert grains.__grains__ == {"a": "aval", "foo": {"is": {"nested": "val"}}} + + with setGrains({"a": "aval", "foo": {"is": {"nested": "val"}}}): + # Clear a grain (set to None) + ret = grains.present(name="foo:is", value=None) + assert ret["result"] is False + assert ret["changes"] == {} + assert ( + ret["comment"] + == "The key 'foo:is' exists but is a dict or a list. Use 'force=True' to overwrite." + ) + assert grains.__grains__ == {"a": "aval", "foo": {"is": {"nested": "val"}}} + + +def test_present_fails_to_set_dict_or_list(): + with setGrains({"a": "aval", "foo": "bar"}): + # Fails to overwrite a grain to a list + ret = grains.present(name="foo", value=["l1", "l2"]) + assert ret["result"] is False + assert ( + ret["comment"] + == "The key 'foo' exists and the given value is a dict or a list. Use 'force=True' to overwrite." + ) + assert ret["changes"] == {} + assert grains.__grains__ == {"a": "aval", "foo": "bar"} + + with setGrains({"a": "aval", "foo": "bar"}): + # Fails setting a grain to a dict + ret = grains.present(name="foo", value={"k1": "v1"}) + assert ret["result"] is False + assert ( + ret["comment"] + == "The key 'foo' exists and the given value is a dict or a list. Use 'force=True' to overwrite." + ) + assert ret["changes"] == {} + assert grains.__grains__ == {"a": "aval", "foo": "bar"} + + with setGrains({"a": "aval", "foo": {"is": {"nested": "bar"}}}): + # Fails to overwrite a nested grain to a list + ret = grains.present(name="foo,is,nested", value=["l1", "l2"], delimiter=",") + assert ret["result"] is False + assert ret["changes"] == {} + assert ( + ret["comment"] + == "The key 'foo:is:nested' exists and the given value is a dict or a list. Use 'force=True' to overwrite." + ) + assert grains.__grains__ == {"a": "aval", "foo": {"is": {"nested": "bar"}}} + + with setGrains({"a": "aval", "foo": {"is": {"nested": "bar"}}}): + # Fails setting a nested grain to a dict + ret = grains.present(name="foo:is:nested", value={"k1": "v1"}) + assert ret["result"] is False + assert ( + ret["comment"] + == "The key 'foo:is:nested' exists and the given value is a dict or a list. Use 'force=True' to overwrite." + ) + assert ret["changes"] == {} + assert grains.__grains__ == {"a": "aval", "foo": {"is": {"nested": "bar"}}} + + +def test_present_fail_merge_dict(): + with setGrains({"a": "aval", "foo": {"k1": "v1"}}): + # Fails setting a grain to a dict + ret = grains.present(name="foo", value={"k2": "v2"}) + assert ret["result"] is False + assert ( + ret["comment"] + == "The key 'foo' exists but is a dict or a list. Use 'force=True' to overwrite." + ) + assert grains.__grains__ == {"a": "aval", "foo": {"k1": "v1"}} + assertGrainFileContent("a: aval\n" + "foo:\n" + " k1: v1\n") + + +def test_present_force_to_set_dict_or_list(): + with setGrains({"a": "aval", "foo": "bar"}): + # Force to overwrite a grain to a list + ret = grains.present(name="foo", value=["l1", "l2"], force=True) + assert ret["result"] is True + assert ret["comment"] == "Set grain foo to ['l1', 'l2']" + assert ret["changes"] == {"foo": ["l1", "l2"]} + assert grains.__grains__ == {"a": "aval", "foo": ["l1", "l2"]} + assertGrainFileContent("a: aval\n" + "foo:\n" + "- l1\n" + "- l2\n") + + with setGrains({"a": "aval", "foo": "bar"}): + # Force setting a grain to a dict + ret = grains.present(name="foo", value={"k1": "v1"}, force=True) + assert ret["result"] is True + assert ret["comment"] == "Set grain foo to {'k1': 'v1'}" + assert ret["changes"] == {"foo": {"k1": "v1"}} + assert grains.__grains__ == {"a": "aval", "foo": {"k1": "v1"}} + assertGrainFileContent("a: aval\n" + "foo:\n" + " k1: v1\n") + + with setGrains({"a": "aval", "foo": {"is": {"nested": "bar"}}}): + # Force to overwrite a nested grain to a list + ret = grains.present( + name="foo,is,nested", value=["l1", "l2"], delimiter=",", force=True + ) + assert ret["result"] is True + assert ret["changes"] == {"foo": {"is": {"nested": ["l1", "l2"]}}} + assert ret["comment"] == "Set grain foo:is:nested to ['l1', 'l2']" + assert grains.__grains__ == { + "a": "aval", + "foo": {"is": {"nested": ["l1", "l2"]}}, + } + assertGrainFileContent( + "a: aval\n" + + "foo:\n" + + " is:\n" + + " nested:\n" + + " - l1\n" + + " - l2\n" + ) + + with setGrains({"a": "aval", "foo": {"is": {"nested": "bar"}, "and": "other"}}): + # Force setting a nested grain to a dict + ret = grains.present(name="foo:is:nested", value={"k1": "v1"}, force=True) + assert ret["result"] is True + assert ret["comment"] == "Set grain foo:is:nested to {'k1': 'v1'}" + assert ret["changes"] == { + "foo": {"is": {"nested": {"k1": "v1"}}, "and": "other"} + } + assert grains.__grains__ == { + "a": "aval", + "foo": {"is": {"nested": {"k1": "v1"}}, "and": "other"}, + } + assertGrainFileContent( + "a: aval\n" + + "foo:\n" + + " and: other\n" + + " is:\n" + + " nested:\n" + + " k1: v1\n" + ) + + +def test_present_fails_to_convert_value_to_key(): + with setGrains({"a": "aval", "foo": "bar"}): + # Fails converting a value to a nested grain key + ret = grains.present(name="foo:is:nested", value={"k1": "v1"}) + assert ret["result"] is False + assert ( + ret["comment"] + == "The key 'foo' value is 'bar', which is different from the provided key 'is'. Use 'force=True' to overwrite." + ) + assert ret["changes"] == {} + + +def test_present_overwrite_test(): + with patch.dict(grains.__opts__, {"test": True}): + with setGrains({"a": "aval", "foo": "bar"}): + # Overwrite an existing grain + ret = grains.present(name="foo", value="newbar") + assert ret["result"] is None + assert ret["changes"] == {"changed": {"foo": "newbar"}} + assert grains.__grains__ == {"a": "aval", "foo": "bar"} + assertGrainFileContent("a: aval\n" + "foo: bar\n") + + +def test_present_convert_value_to_key(): + with setGrains({"a": "aval", "foo": "is"}): + # Converts a value to a nested grain key + ret = grains.present(name="foo:is:nested", value={"k1": "v1"}) + assert ret["result"] is True + assert ret["comment"] == "Set grain foo:is:nested to {'k1': 'v1'}" + assert ret["changes"] == {"foo": {"is": {"nested": {"k1": "v1"}}}} + assert grains.__grains__ == { + "a": "aval", + "foo": {"is": {"nested": {"k1": "v1"}}}, + } + assertGrainFileContent( + "a: aval\n" + "foo:\n" + " is:\n" + " nested:\n" + " k1: v1\n" + ) + + with setGrains({"a": "aval", "foo": ["one", "is", "correct"]}): + # Converts a list element to a nested grain key + ret = grains.present(name="foo:is:nested", value={"k1": "v1"}) + assert ret["result"] is True + assert ret["comment"] == "Set grain foo:is:nested to {'k1': 'v1'}" + assert ret["changes"] == { + "foo": ["one", {"is": {"nested": {"k1": "v1"}}}, "correct"] + } + assert grains.__grains__ == { + "a": "aval", + "foo": ["one", {"is": {"nested": {"k1": "v1"}}}, "correct"], + } + assertGrainFileContent( + "a: aval\n" + + "foo:\n" + + "- one\n" + + "- is:\n" + + " nested:\n" + + " k1: v1\n" + + "- correct\n" + ) + + +def test_present_unknown_failure(): + with patch("salt.modules.grains.setval") as mocked_setval: + mocked_setval.return_value = "Failed to set grain foo" + with setGrains({"a": "aval", "foo": "bar"}): + # Unknown reason failure + ret = grains.present(name="foo", value="baz") + assert ret["result"] is False + assert ret["comment"] == "Failed to set grain foo" + assert ret["changes"] == {} + assert grains.__grains__ == {"a": "aval", "foo": "bar"} + assertGrainFileContent("a: aval\n" + "foo: bar\n") + + +# 'absent' function tests: 6 + + +def test_absent_already(): + # Unset a non existent grain + with setGrains({"a": "aval"}): + ret = grains.absent(name="foo") + assert ret["result"] is True + assert ret["comment"] == "Grain foo does not exist" + assert ret["changes"] == {} + assert grains.__grains__ == {"a": "aval"} + assertGrainFileContent("a: aval\n") + + # Unset a non existent nested grain + with setGrains({"a": "aval"}): + ret = grains.absent(name="foo:is:nested") + assert ret["result"] is True + assert ret["comment"] == "Grain foo:is:nested does not exist" + assert ret["changes"] == {} + assert grains.__grains__ == {"a": "aval"} + assertGrainFileContent("a: aval\n") + + +def test_absent_unset(): + # Unset a grain + with setGrains({"a": "aval", "foo": "bar"}): + ret = grains.absent(name="foo") + assert ret["result"] is True + assert ret["comment"] == "Value for grain foo was set to None" + assert ret["changes"] == {"grain": "foo", "value": None} + assert grains.__grains__ == {"a": "aval", "foo": None} + assertGrainFileContent("a: aval\n" + "foo: null\n") + + # Unset grain when its value is False + with setGrains({"a": "aval", "foo": False}): + ret = grains.absent(name="foo") + assert ret["result"] is True + assert ret["comment"] == "Value for grain foo was set to None" + assert ret["changes"] == {"grain": "foo", "value": None} + assert grains.__grains__ == {"a": "aval", "foo": None} + assertGrainFileContent("a: aval\n" + "foo: null\n") + + # Unset a nested grain + with setGrains( + {"a": "aval", "foo": ["order", {"is": {"nested": "bar"}}, "correct"]} + ): + ret = grains.absent(name="foo,is,nested", delimiter=",") + assert ret["result"] is True + assert ret["comment"] == "Value for grain foo:is:nested was set to None" + assert ret["changes"] == {"grain": "foo:is:nested", "value": None} + assert grains.__grains__ == { + "a": "aval", + "foo": ["order", {"is": {"nested": None}}, "correct"], + } + assertGrainFileContent( + "a: aval\n" + + "foo:\n" + + "- order\n" + + "- is:\n" + + " nested: null\n" + + "- correct\n" + ) + + # Unset a nested value don't change anything + with setGrains({"a": "aval", "foo": ["order", {"is": "nested"}, "correct"]}): + ret = grains.absent(name="foo:is:nested") + assert ret["result"] is True + assert ret["comment"] == "Grain foo:is:nested does not exist" + assert ret["changes"] == {} + assert grains.__grains__ == { + "a": "aval", + "foo": ["order", {"is": "nested"}, "correct"], + } + assertGrainFileContent( + "a: aval\n" + "foo:\n" + "- order\n" + "- is: nested\n" + "- correct\n" + ) + + +def test_absent_unset_test(): + with patch.dict(grains.__opts__, {"test": True}): + with setGrains({"a": "aval", "foo": "bar"}): + # Overwrite an existing grain + ret = grains.absent(name="foo") + assert ret["result"] is None + assert ret["changes"] == {"grain": "foo", "value": None} + assert grains.__grains__ == {"a": "aval", "foo": "bar"} + assertGrainFileContent("a: aval\n" + "foo: bar\n") + + +def test_absent_fails_nested_complex_grain(): + # Unset a nested complex grain + with setGrains( + {"a": "aval", "foo": ["order", {"is": {"nested": "bar"}}, "correct"]} + ): + ret = grains.absent(name="foo:is") + assert ret["result"] is False + assert ( + ret["comment"] + == "The key 'foo:is' exists but is a dict or a list. Use 'force=True' to overwrite." + ) + assert ret["changes"] == {} + assert grains.__grains__ == { + "a": "aval", + "foo": ["order", {"is": {"nested": "bar"}}, "correct"], + } + assertGrainFileContent( + "a: aval\n" + + "foo:\n" + + "- order\n" + + "- is:\n" + + " nested: bar\n" + + "- correct\n" + ) + + +def test_absent_force_nested_complex_grain(): + # Unset a nested complex grain + with setGrains( + {"a": "aval", "foo": ["order", {"is": {"nested": "bar"}}, "correct"]} + ): + ret = grains.absent(name="foo:is", force=True) + assert ret["result"] is True + assert ret["comment"] == "Value for grain foo:is was set to None" + assert ret["changes"] == {"grain": "foo:is", "value": None} + assert grains.__grains__ == { + "a": "aval", + "foo": ["order", {"is": None}, "correct"], + } + assertGrainFileContent( + "a: aval\n" + "foo:\n" + "- order\n" + "- is: null\n" + "- correct\n" + ) + + +def test_absent_delete(): + # Delete a grain + with setGrains({"a": "aval", "foo": "bar"}): + ret = grains.absent(name="foo", destructive=True) + assert ret["result"] is True + assert ret["comment"] == "Grain foo was deleted" + assert ret["changes"] == {"deleted": "foo"} + assert grains.__grains__ == {"a": "aval"} + assertGrainFileContent("a: aval\n") + + # Delete a previously unset grain + with setGrains({"a": "aval", "foo": None}): + ret = grains.absent(name="foo", destructive=True) + assert ret["result"] is True + assert ret["comment"] == "Grain foo was deleted" + assert ret["changes"] == {"deleted": "foo"} + assert grains.__grains__ == {"a": "aval"} + assertGrainFileContent("a: aval\n") + + # Delete a nested grain + with setGrains( + { + "a": "aval", + "foo": [ + "order", + {"is": {"nested": "bar", "other": "value"}}, + "correct", + ], + } + ): + ret = grains.absent(name="foo:is:nested", destructive=True) + assert ret["result"] is True + assert ret["comment"] == "Grain foo:is:nested was deleted" + assert ret["changes"] == {"deleted": "foo:is:nested"} + assert grains.__grains__ == { + "a": "aval", + "foo": ["order", {"is": {"other": "value"}}, "correct"], + } + assertGrainFileContent( + "a: aval\n" + + "foo:\n" + + "- order\n" + + "- is:\n" + + " other: value\n" + + "- correct\n" + ) + + +# 'append' function tests: 6 + + +def test_append(): + # Append to an existing list + with setGrains({"a": "aval", "foo": ["bar"]}): + ret = grains.append(name="foo", value="baz") + assert ret["result"] is True + assert ret["comment"] == "Value baz was added to grain foo" + assert ret["changes"] == {"added": "baz"} + assert grains.__grains__ == {"a": "aval", "foo": ["bar", "baz"]} + assertGrainFileContent("a: aval\n" + "foo:\n" + "- bar\n" + "- baz\n") + + +def test_append_nested(): + # Append to an existing nested list + with setGrains({"a": "aval", "foo": {"list": ["bar"]}}): + ret = grains.append(name="foo,list", value="baz", delimiter=",") + assert ret["result"] is True + assert ret["comment"] == "Value baz was added to grain foo:list" + assert ret["changes"] == {"added": "baz"} + assert grains.__grains__ == {"a": "aval", "foo": {"list": ["bar", "baz"]}} + assertGrainFileContent( + "a: aval\n" + "foo:\n" + " list:\n" + " - bar\n" + " - baz\n" + ) + + +def test_append_already(): + # Append to an existing list + with setGrains({"a": "aval", "foo": ["bar"]}): + ret = grains.append(name="foo", value="bar") + assert ret["result"] is True + assert ret["comment"] == "Value bar is already in the list " + "for grain foo" + assert ret["changes"] == {} + assert grains.__grains__ == {"a": "aval", "foo": ["bar"]} + assertGrainFileContent("a: aval\n" + "foo:\n" + "- bar\n") + + +def test_append_fails_not_a_list(): + # Fail to append to an existing grain, not a list + with setGrains({"a": "aval", "foo": {"bar": "val"}}): + ret = grains.append(name="foo", value="baz") + assert ret["result"] is False + assert ret["comment"] == "Grain foo is not a valid list" + assert ret["changes"] == {} + assert grains.__grains__ == {"a": "aval", "foo": {"bar": "val"}} + + +def test_append_convert_to_list(): + # Append to an existing grain, converting to a list + with setGrains({"a": "aval", "foo": {"bar": "val"}}): + assertGrainFileContent("a: aval\n" + "foo:\n" + " bar: val\n") + ret = grains.append(name="foo", value="baz", convert=True) + assert ret["result"] is True + assert ret["comment"] == "Value baz was added to grain foo" + assert ret["changes"] == {"added": "baz"} + assert grains.__grains__ == {"a": "aval", "foo": [{"bar": "val"}, "baz"]} + assertGrainFileContent("a: aval\n" + "foo:\n" + "- bar: val\n" + "- baz\n") + + # Append to an existing grain, converting to a list a multi-value dict + with setGrains({"a": "aval", "foo": {"bar": "val", "other": "value"}}): + assertGrainFileContent( + "a: aval\n" + "foo:\n" + " bar: val\n" + " other: value\n" + ) + ret = grains.append(name="foo", value="baz", convert=True) + assert ret["result"] is True + assert ret["comment"] == "Value baz was added to grain foo" + assert ret["changes"] == {"added": "baz"} + assert grains.__grains__ == { + "a": "aval", + "foo": [{"bar": "val", "other": "value"}, "baz"], + } + assertGrainFileContent( + "a: aval\n" + "foo:\n" + "- bar: val\n" + " other: value\n" + "- baz\n" + ) + + +def test_append_fails_inexistent(): + # Append to a non existing grain + with setGrains({"a": "aval"}): + ret = grains.append(name="foo", value="bar") + assert ret["result"] is False + assert ret["comment"] == "Grain foo does not exist" + assert ret["changes"] == {} + assert grains.__grains__ == {"a": "aval"} + + +def test_append_convert_to_list_empty(): + # Append to an existing list + with setGrains({"foo": None}): + ret = grains.append(name="foo", value="baz", convert=True) + assert ret["result"] is True + assert ret["comment"] == "Value baz was added to grain foo" + assert ret["changes"] == {"added": "baz"} + assert grains.__grains__ == {"foo": ["baz"]} + assertGrainFileContent("foo:\n" + "- baz\n") + + +# 'list_present' function tests: 7 + + +def test_list_present(): + with setGrains({"a": "aval", "foo": ["bar"]}): + ret = grains.list_present(name="foo", value="baz") + assert ret["result"] is True + assert ret["comment"] == "Append value baz to grain foo" + assert ret["changes"] == {"new": {"foo": ["bar", "baz"]}} + assert grains.__grains__ == {"a": "aval", "foo": ["bar", "baz"]} + assertGrainFileContent("a: aval\n" + "foo:\n" + "- bar\n" + "- baz\n") + + +def test_list_present_nested(): + with setGrains({"a": "aval", "foo": {"is": {"nested": ["bar"]}}}): + ret = grains.list_present(name="foo,is,nested", value="baz", delimiter=",") + assert ret["result"] is True + assert ret["comment"] == "Append value baz to grain foo:is:nested" + assert ret["changes"] == {"new": {"foo": {"is": {"nested": ["bar", "baz"]}}}} + assert grains.__grains__ == { + "a": "aval", + "foo": {"is": {"nested": ["bar", "baz"]}}, + } + assertGrainFileContent( + "a: aval\n" + + "foo:\n" + + " is:\n" + + " nested:\n" + + " - bar\n" + + " - baz\n" + ) + + +def test_list_present_inexistent(): + with setGrains({"a": "aval"}): + ret = grains.list_present(name="foo", value="baz") + assert ret["result"] is True + assert ret["comment"] == "Append value baz to grain foo" + assert ret["changes"] == {"new": {"foo": ["baz"]}} + assert grains.__grains__ == {"a": "aval", "foo": ["baz"]} + assertGrainFileContent("a: aval\n" + "foo:\n" + "- baz\n") + + +def test_list_present_inexistent_nested(): + with setGrains({"a": "aval"}): + ret = grains.list_present(name="foo:is:nested", value="baz") + assert ret["result"] is True + assert ret["comment"] == "Append value baz to grain foo:is:nested" + assert ret["changes"] == {"new": {"foo": {"is": {"nested": ["baz"]}}}} + assert grains.__grains__ == {"a": "aval", "foo": {"is": {"nested": ["baz"]}}} + assertGrainFileContent( + "a: aval\n" + "foo:\n" + " is:\n" + " nested:\n" + " - baz\n" + ) + + +def test_list_present_not_a_list(): + with setGrains({"a": "aval", "foo": "bar"}): + ret = grains.list_present(name="foo", value="baz") + assert ret["result"] is False + assert ret["comment"] == "Grain foo is not a valid list" + assert ret["changes"] == {} + assert grains.__grains__ == {"a": "aval", "foo": "bar"} + assertGrainFileContent("a: aval\n" + "foo: bar\n") + + +def test_list_present_nested_already(): + with setGrains({"a": "aval", "b": {"foo": ["bar"]}}): + ret = grains.list_present(name="b:foo", value="bar") + assert ret["result"] is True + assert ret["comment"] == "Value bar is already in grain b:foo" + assert ret["changes"] == {} + assert grains.__grains__ == {"a": "aval", "b": {"foo": ["bar"]}} + assertGrainFileContent("a: aval\n" + "b:\n" + " foo:\n" + " - bar\n") + + +def test_list_present_already(): + with setGrains({"a": "aval", "foo": ["bar"]}): + ret = grains.list_present(name="foo", value="bar") + assert ret["result"] is True + assert ret["comment"] == "Value bar is already in grain foo" + assert ret["changes"] == {} + assert grains.__grains__ == {"a": "aval", "foo": ["bar"]} + assertGrainFileContent("a: aval\n" + "foo:\n" + "- bar\n") + + +def test_list_present_unknown_failure(): + with setGrains({"a": "aval", "foo": ["bar"]}): + # Unknown reason failure + + with patch.dict(grainsmod.__salt__, {"grains.append": MagicMock()}): + ret = grains.list_present(name="foo", value="baz") + assert ret["result"] is False + assert ret["comment"] == "Failed append value baz to grain foo" + assert ret["changes"] == {} + assert grains.__grains__ == {"a": "aval", "foo": ["bar"]} + assertGrainFileContent("a: aval\n" + "foo:\n" + "- bar\n") + + +# 'list_absent' function tests: 6 + + +def test_list_absent(): + with setGrains({"a": "aval", "foo": ["bar"]}): + ret = grains.list_absent(name="foo", value="bar") + assert ret["result"] is True + assert ret["comment"] == "Value bar was deleted from grain foo" + assert ret["changes"] == {"deleted": ["bar"]} + assert grains.__grains__ == {"a": "aval", "foo": []} + assertGrainFileContent("a: aval\n" + "foo: []\n") + + +def test_list_absent_nested(): + with setGrains({"a": "aval", "foo": {"list": ["bar"]}}): + ret = grains.list_absent(name="foo:list", value="bar") + assert ret["result"] is True + assert ret["comment"] == "Value bar was deleted from grain foo:list" + assert ret["changes"] == {"deleted": ["bar"]} + assert grains.__grains__ == {"a": "aval", "foo": {"list": []}} + assertGrainFileContent("a: aval\n" + "foo:\n" + " list: []\n") + + +def test_list_absent_inexistent(): + with setGrains({"a": "aval"}): + ret = grains.list_absent(name="foo", value="baz") + assert ret["result"] is True + assert ret["comment"] == "Grain foo does not exist" + assert ret["changes"] == {} + assert grains.__grains__ == {"a": "aval"} + assertGrainFileContent("a: aval\n") + + +def test_list_absent_inexistent_nested(): + with setGrains({"a": "aval"}): + ret = grains.list_absent(name="foo:list", value="baz") + assert ret["result"] is True + assert ret["comment"] == "Grain foo:list does not exist" + assert ret["changes"] == {} + assert grains.__grains__ == {"a": "aval"} + assertGrainFileContent("a: aval\n") + + +def test_list_absent_not_a_list(): + with setGrains({"a": "aval", "foo": "bar"}): + ret = grains.list_absent(name="foo", value="bar") + assert ret["result"] is False + assert ret["comment"] == "Grain foo is not a valid list" + assert ret["changes"] == {} + assert grains.__grains__ == {"a": "aval", "foo": "bar"} + assertGrainFileContent("a: aval\n" + "foo: bar\n") + + +def test_list_absent_already(): + with setGrains({"a": "aval", "foo": ["bar"]}): + ret = grains.list_absent(name="foo", value="baz") + assert ret["result"] is True + assert ret["comment"] == "Value baz is absent from grain foo" + assert ret["changes"] == {} + assert grains.__grains__ == {"a": "aval", "foo": ["bar"]} + assertGrainFileContent("a: aval\n" + "foo:\n" + "- bar\n") diff --git a/tests/unit/states/test_grains.py b/tests/unit/states/test_grains.py deleted file mode 100644 index 759ed27d545..00000000000 --- a/tests/unit/states/test_grains.py +++ /dev/null @@ -1,897 +0,0 @@ -""" -unit tests for the grains state -""" - - -import contextlib -import os - -import salt.modules.grains as grainsmod -import salt.states.grains as grains -import salt.utils.files -import salt.utils.stringutils -import salt.utils.yaml -from tests.support.mixins import LoaderModuleMockMixin -from tests.support.mock import MagicMock, patch -from tests.support.runtests import RUNTIME_VARS -from tests.support.unit import TestCase - - -class GrainsTestCase(TestCase, LoaderModuleMockMixin): - def setup_loader_modules(self): - grains_test_dir = "__salt_test_state_grains" - if not os.path.exists(os.path.join(RUNTIME_VARS.TMP, grains_test_dir)): - os.makedirs(os.path.join(RUNTIME_VARS.TMP, grains_test_dir)) - loader_globals = { - "__opts__": { - "test": False, - "conf_file": os.path.join(RUNTIME_VARS.TMP, grains_test_dir, "minion"), - "cachedir": os.path.join(RUNTIME_VARS.TMP, grains_test_dir), - "local": True, - }, - "__salt__": { - "cmd.run_all": MagicMock( - return_value={"pid": 5, "retcode": 0, "stderr": "", "stdout": ""} - ), - "grains.get": grainsmod.get, - "grains.set": grainsmod.set, - "grains.setval": grainsmod.setval, - "grains.delval": grainsmod.delval, - "grains.append": grainsmod.append, - "grains.remove": grainsmod.remove, - "saltutil.sync_grains": MagicMock(), - }, - } - return {grains: loader_globals, grainsmod: loader_globals} - - def assertGrainFileContent(self, grains_string): - if os.path.isdir(grains.__opts__["conf_file"]): - grains_file = os.path.join(grains.__opts__["conf_file"], "grains") - else: - grains_file = os.path.join( - os.path.dirname(grains.__opts__["conf_file"]), "grains" - ) - with salt.utils.files.fopen(grains_file, "r") as grf: - grains_data = salt.utils.stringutils.to_unicode(grf.read()) - self.assertMultiLineEqual(grains_string, grains_data) - - @contextlib.contextmanager - def setGrains(self, grains_data): - with patch.dict(grains.__grains__, grains_data): - with patch.dict(grainsmod.__grains__, grains_data): - if os.path.isdir(grains.__opts__["conf_file"]): - grains_file = os.path.join(grains.__opts__["conf_file"], "grains") - else: - grains_file = os.path.join( - os.path.dirname(grains.__opts__["conf_file"]), "grains" - ) - with salt.utils.files.fopen(grains_file, "w+") as grf: - salt.utils.yaml.safe_dump( - grains_data, grf, default_flow_style=False - ) - yield - - # 'exists' function tests: 2 - - def test_exists_missing(self): - with self.setGrains({"a": "aval"}): - ret = grains.exists(name="foo") - self.assertEqual(ret["result"], False) - self.assertEqual(ret["comment"], "Grain does not exist") - self.assertEqual(ret["changes"], {}) - - def test_exists_found(self): - with self.setGrains({"a": "aval", "foo": "bar"}): - # Grain already set - ret = grains.exists(name="foo") - self.assertEqual(ret["result"], True) - self.assertEqual(ret["comment"], "Grain exists") - self.assertEqual(ret["changes"], {}) - - # 'make_hashable' function tests: 1 - - def test_make_hashable(self): - with self.setGrains({"cmplx_lst_grain": [{"a": "aval"}, {"foo": "bar"}]}): - hashable_list = {"cmplx_lst_grain": [{"a": "aval"}, {"foo": "bar"}]} - self.assertEqual( - grains.make_hashable(grains.__grains__).issubset( - grains.make_hashable(hashable_list) - ), - True, - ) - - # 'present' function tests: 12 - - def test_present_add(self): - # Set a non existing grain - with self.setGrains({"a": "aval"}): - ret = grains.present(name="foo", value="bar") - self.assertEqual(ret["result"], True) - self.assertEqual(ret["changes"], {"foo": "bar"}) - self.assertEqual(grains.__grains__, {"a": "aval", "foo": "bar"}) - self.assertGrainFileContent("a: aval\nfoo: bar\n") - - # Set a non existing nested grain - with self.setGrains({"a": "aval"}): - ret = grains.present(name="foo:is:nested", value="bar") - self.assertEqual(ret["result"], True) - self.assertEqual(ret["changes"], {"foo": {"is": {"nested": "bar"}}}) - self.assertEqual( - grains.__grains__, {"a": "aval", "foo": {"is": {"nested": "bar"}}} - ) - self.assertGrainFileContent("a: aval\nfoo:\n is:\n nested: bar\n") - - # Set a non existing nested dict grain - with self.setGrains({"a": "aval"}): - ret = grains.present(name="foo:is:nested", value={"bar": "is a dict"}) - self.assertEqual(ret["result"], True) - self.assertEqual( - ret["changes"], {"foo": {"is": {"nested": {"bar": "is a dict"}}}} - ) - self.assertEqual( - grains.__grains__, - {"a": "aval", "foo": {"is": {"nested": {"bar": "is a dict"}}}}, - ) - self.assertGrainFileContent( - "a: aval\n" - + "foo:\n" - + " is:\n" - + " nested:\n" - + " bar: is a dict\n" - ) - - def test_present_add_key_to_existing(self): - with self.setGrains({"a": "aval", "foo": {"k1": "v1"}}): - # Fails setting a grain to a dict - ret = grains.present(name="foo:k2", value="v2") - self.assertEqual(ret["result"], True) - self.assertEqual(ret["comment"], "Set grain foo:k2 to v2") - self.assertEqual(ret["changes"], {"foo": {"k2": "v2", "k1": "v1"}}) - self.assertEqual( - grains.__grains__, {"a": "aval", "foo": {"k1": "v1", "k2": "v2"}} - ) - self.assertGrainFileContent( - "a: aval\n" + "foo:\n" + " k1: v1\n" + " k2: v2\n" - ) - - def test_present_already_set(self): - with self.setGrains({"a": "aval", "foo": "bar"}): - # Grain already set - ret = grains.present(name="foo", value="bar") - self.assertEqual(ret["result"], True) - self.assertEqual(ret["comment"], "Grain is already set") - self.assertEqual(ret["changes"], {}) - self.assertEqual(grains.__grains__, {"a": "aval", "foo": "bar"}) - - with self.setGrains({"a": "aval", "foo": {"is": {"nested": "bar"}}}): - # Nested grain already set - ret = grains.present(name="foo:is:nested", value="bar") - self.assertEqual(ret["result"], True) - self.assertEqual(ret["comment"], "Grain is already set") - self.assertEqual(ret["changes"], {}) - self.assertEqual( - grains.__grains__, {"a": "aval", "foo": {"is": {"nested": "bar"}}} - ) - - with self.setGrains({"a": "aval", "foo": {"is": {"nested": "bar"}}}): - # Nested dict grain already set - ret = grains.present(name="foo:is", value={"nested": "bar"}) - self.assertEqual(ret["result"], True) - self.assertEqual(ret["comment"], "Grain is already set") - self.assertEqual(ret["changes"], {}) - self.assertEqual( - grains.__grains__, {"a": "aval", "foo": {"is": {"nested": "bar"}}} - ) - - def test_present_overwrite(self): - with self.setGrains({"a": "aval", "foo": "bar"}): - # Overwrite an existing grain - ret = grains.present(name="foo", value="newbar") - self.assertEqual(ret["result"], True) - self.assertEqual(ret["changes"], {"foo": "newbar"}) - self.assertEqual(grains.__grains__, {"a": "aval", "foo": "newbar"}) - self.assertGrainFileContent("a: aval\n" + "foo: newbar\n") - - with self.setGrains({"a": "aval", "foo": "bar"}): - # Clear a grain (set to None) - ret = grains.present(name="foo", value=None) - self.assertEqual(ret["result"], True) - self.assertEqual(ret["changes"], {"foo": None}) - self.assertEqual(grains.__grains__, {"a": "aval", "foo": None}) - self.assertGrainFileContent("a: aval\n" + "foo: null\n") - - with self.setGrains({"a": "aval", "foo": {"is": {"nested": "bar"}}}): - # Overwrite an existing nested grain - ret = grains.present(name="foo:is:nested", value="newbar") - self.assertEqual(ret["result"], True) - self.assertEqual(ret["changes"], {"foo": {"is": {"nested": "newbar"}}}) - self.assertEqual( - grains.__grains__, {"a": "aval", "foo": {"is": {"nested": "newbar"}}} - ) - self.assertGrainFileContent( - "a: aval\n" + "foo:\n" + " is:\n" + " nested: newbar\n" - ) - - with self.setGrains({"a": "aval", "foo": {"is": {"nested": "bar"}}}): - # Clear a nested grain (set to None) - ret = grains.present(name="foo:is:nested", value=None) - self.assertEqual(ret["result"], True) - self.assertEqual(ret["changes"], {"foo": {"is": {"nested": None}}}) - self.assertEqual( - grains.__grains__, {"a": "aval", "foo": {"is": {"nested": None}}} - ) - self.assertGrainFileContent( - "a: aval\n" + "foo:\n" + " is:\n" + " nested: null\n" - ) - - def test_present_fail_overwrite(self): - with self.setGrains({"a": "aval", "foo": {"is": {"nested": "val"}}}): - # Overwrite an existing grain - ret = grains.present(name="foo:is", value="newbar") - self.assertEqual(ret["result"], False) - self.assertEqual(ret["changes"], {}) - self.assertEqual( - ret["comment"], - "The key 'foo:is' exists but is a dict or a list. Use 'force=True' to" - " overwrite.", - ) - self.assertEqual( - grains.__grains__, {"a": "aval", "foo": {"is": {"nested": "val"}}} - ) - - with self.setGrains({"a": "aval", "foo": {"is": {"nested": "val"}}}): - # Clear a grain (set to None) - ret = grains.present(name="foo:is", value=None) - self.assertEqual(ret["result"], False) - self.assertEqual(ret["changes"], {}) - self.assertEqual( - ret["comment"], - "The key 'foo:is' exists but is a dict or a list. Use 'force=True' to" - " overwrite.", - ) - self.assertEqual( - grains.__grains__, {"a": "aval", "foo": {"is": {"nested": "val"}}} - ) - - def test_present_fails_to_set_dict_or_list(self): - with self.setGrains({"a": "aval", "foo": "bar"}): - # Fails to overwrite a grain to a list - ret = grains.present(name="foo", value=["l1", "l2"]) - self.assertEqual(ret["result"], False) - self.assertEqual( - ret["comment"], - "The key 'foo' exists and the " - + "given value is a dict or a list. " - + "Use 'force=True' to overwrite.", - ) - self.assertEqual(ret["changes"], {}) - self.assertEqual(grains.__grains__, {"a": "aval", "foo": "bar"}) - - with self.setGrains({"a": "aval", "foo": "bar"}): - # Fails setting a grain to a dict - ret = grains.present(name="foo", value={"k1": "v1"}) - self.assertEqual(ret["result"], False) - self.assertEqual( - ret["comment"], - "The key 'foo' exists and the given " - + "value is a dict or a list. Use " - + "'force=True' to overwrite.", - ) - self.assertEqual(ret["changes"], {}) - self.assertEqual(grains.__grains__, {"a": "aval", "foo": "bar"}) - - with self.setGrains({"a": "aval", "foo": {"is": {"nested": "bar"}}}): - # Fails to overwrite a nested grain to a list - ret = grains.present( - name="foo,is,nested", value=["l1", "l2"], delimiter="," - ) - self.assertEqual(ret["result"], False) - self.assertEqual(ret["changes"], {}) - self.assertEqual( - ret["comment"], - "The key 'foo:is:nested' exists and the " - + "given value is a dict or a list. " - + "Use 'force=True' to overwrite.", - ) - self.assertEqual( - grains.__grains__, {"a": "aval", "foo": {"is": {"nested": "bar"}}} - ) - - with self.setGrains({"a": "aval", "foo": {"is": {"nested": "bar"}}}): - # Fails setting a nested grain to a dict - ret = grains.present(name="foo:is:nested", value={"k1": "v1"}) - self.assertEqual(ret["result"], False) - self.assertEqual( - ret["comment"], - "The key 'foo:is:nested' exists and the " - + "given value is a dict or a list. " - + "Use 'force=True' to overwrite.", - ) - self.assertEqual(ret["changes"], {}) - self.assertEqual( - grains.__grains__, {"a": "aval", "foo": {"is": {"nested": "bar"}}} - ) - - def test_present_fail_merge_dict(self): - with self.setGrains({"a": "aval", "foo": {"k1": "v1"}}): - # Fails setting a grain to a dict - ret = grains.present(name="foo", value={"k2": "v2"}) - self.assertEqual(ret["result"], False) - self.assertEqual( - ret["comment"], - "The key 'foo' exists but " - + "is a dict or a list. " - + "Use 'force=True' to overwrite.", - ) - self.assertEqual(grains.__grains__, {"a": "aval", "foo": {"k1": "v1"}}) - self.assertGrainFileContent("a: aval\n" + "foo:\n" + " k1: v1\n") - - def test_present_force_to_set_dict_or_list(self): - with self.setGrains({"a": "aval", "foo": "bar"}): - # Force to overwrite a grain to a list - ret = grains.present(name="foo", value=["l1", "l2"], force=True) - self.assertEqual(ret["result"], True) - self.assertEqual(ret["comment"], "Set grain foo to ['l1', 'l2']") - self.assertEqual(ret["changes"], {"foo": ["l1", "l2"]}) - self.assertEqual(grains.__grains__, {"a": "aval", "foo": ["l1", "l2"]}) - self.assertGrainFileContent("a: aval\n" + "foo:\n" + "- l1\n" + "- l2\n") - - with self.setGrains({"a": "aval", "foo": "bar"}): - # Force setting a grain to a dict - ret = grains.present(name="foo", value={"k1": "v1"}, force=True) - self.assertEqual(ret["result"], True) - self.assertEqual(ret["comment"], "Set grain foo to {'k1': 'v1'}") - self.assertEqual(ret["changes"], {"foo": {"k1": "v1"}}) - self.assertEqual(grains.__grains__, {"a": "aval", "foo": {"k1": "v1"}}) - self.assertGrainFileContent("a: aval\n" + "foo:\n" + " k1: v1\n") - - with self.setGrains({"a": "aval", "foo": {"is": {"nested": "bar"}}}): - # Force to overwrite a nested grain to a list - ret = grains.present( - name="foo,is,nested", value=["l1", "l2"], delimiter=",", force=True - ) - self.assertEqual(ret["result"], True) - self.assertEqual(ret["changes"], {"foo": {"is": {"nested": ["l1", "l2"]}}}) - self.assertEqual(ret["comment"], "Set grain foo:is:nested to ['l1', 'l2']") - self.assertEqual( - grains.__grains__, - {"a": "aval", "foo": {"is": {"nested": ["l1", "l2"]}}}, - ) - self.assertGrainFileContent( - "a: aval\n" - + "foo:\n" - + " is:\n" - + " nested:\n" - + " - l1\n" - + " - l2\n" - ) - - with self.setGrains( - {"a": "aval", "foo": {"is": {"nested": "bar"}, "and": "other"}} - ): - # Force setting a nested grain to a dict - ret = grains.present(name="foo:is:nested", value={"k1": "v1"}, force=True) - self.assertEqual(ret["result"], True) - self.assertEqual(ret["comment"], "Set grain foo:is:nested to {'k1': 'v1'}") - self.assertEqual( - ret["changes"], - {"foo": {"is": {"nested": {"k1": "v1"}}, "and": "other"}}, - ) - self.assertEqual( - grains.__grains__, - {"a": "aval", "foo": {"is": {"nested": {"k1": "v1"}}, "and": "other"}}, - ) - self.assertGrainFileContent( - "a: aval\n" - + "foo:\n" - + " and: other\n" - + " is:\n" - + " nested:\n" - + " k1: v1\n" - ) - - def test_present_fails_to_convert_value_to_key(self): - with self.setGrains({"a": "aval", "foo": "bar"}): - # Fails converting a value to a nested grain key - ret = grains.present(name="foo:is:nested", value={"k1": "v1"}) - self.assertEqual(ret["result"], False) - self.assertEqual( - ret["comment"], - "The key 'foo' value is 'bar', " - + "which is different from the provided " - + "key 'is'. Use 'force=True' to overwrite.", - ) - self.assertEqual(ret["changes"], {}) - - def test_present_overwrite_test(self): - with patch.dict(grains.__opts__, {"test": True}): - with self.setGrains({"a": "aval", "foo": "bar"}): - # Overwrite an existing grain - ret = grains.present(name="foo", value="newbar") - self.assertEqual(ret["result"], None) - self.assertEqual(ret["changes"], {"changed": {"foo": "newbar"}}) - self.assertEqual(grains.__grains__, {"a": "aval", "foo": "bar"}) - self.assertGrainFileContent("a: aval\n" + "foo: bar\n") - - def test_present_convert_value_to_key(self): - with self.setGrains({"a": "aval", "foo": "is"}): - # Converts a value to a nested grain key - ret = grains.present(name="foo:is:nested", value={"k1": "v1"}) - self.assertEqual(ret["result"], True) - self.assertEqual(ret["comment"], "Set grain foo:is:nested to {'k1': 'v1'}") - self.assertEqual(ret["changes"], {"foo": {"is": {"nested": {"k1": "v1"}}}}) - self.assertEqual( - grains.__grains__, - {"a": "aval", "foo": {"is": {"nested": {"k1": "v1"}}}}, - ) - self.assertGrainFileContent( - "a: aval\n" + "foo:\n" + " is:\n" + " nested:\n" + " k1: v1\n" - ) - - with self.setGrains({"a": "aval", "foo": ["one", "is", "correct"]}): - # Converts a list element to a nested grain key - ret = grains.present(name="foo:is:nested", value={"k1": "v1"}) - self.assertEqual(ret["result"], True) - self.assertEqual(ret["comment"], "Set grain foo:is:nested to {'k1': 'v1'}") - self.assertEqual( - ret["changes"], - {"foo": ["one", {"is": {"nested": {"k1": "v1"}}}, "correct"]}, - ) - self.assertEqual( - grains.__grains__, - { - "a": "aval", - "foo": ["one", {"is": {"nested": {"k1": "v1"}}}, "correct"], - }, - ) - self.assertGrainFileContent( - "a: aval\n" - + "foo:\n" - + "- one\n" - + "- is:\n" - + " nested:\n" - + " k1: v1\n" - + "- correct\n" - ) - - def test_present_unknown_failure(self): - with patch("salt.modules.grains.setval") as mocked_setval: - mocked_setval.return_value = "Failed to set grain foo" - with self.setGrains({"a": "aval", "foo": "bar"}): - # Unknown reason failure - ret = grains.present(name="foo", value="baz") - self.assertEqual(ret["result"], False) - self.assertEqual(ret["comment"], "Failed to set grain foo") - self.assertEqual(ret["changes"], {}) - self.assertEqual(grains.__grains__, {"a": "aval", "foo": "bar"}) - self.assertGrainFileContent("a: aval\n" + "foo: bar\n") - - # 'absent' function tests: 6 - - def test_absent_already(self): - # Unset a non existent grain - with self.setGrains({"a": "aval"}): - ret = grains.absent(name="foo") - self.assertEqual(ret["result"], True) - self.assertEqual(ret["comment"], "Grain foo does not exist") - self.assertEqual(ret["changes"], {}) - self.assertEqual(grains.__grains__, {"a": "aval"}) - self.assertGrainFileContent("a: aval\n") - - # Unset a non existent nested grain - with self.setGrains({"a": "aval"}): - ret = grains.absent(name="foo:is:nested") - self.assertEqual(ret["result"], True) - self.assertEqual(ret["comment"], "Grain foo:is:nested does not exist") - self.assertEqual(ret["changes"], {}) - self.assertEqual(grains.__grains__, {"a": "aval"}) - self.assertGrainFileContent("a: aval\n") - - def test_absent_unset(self): - # Unset a grain - with self.setGrains({"a": "aval", "foo": "bar"}): - ret = grains.absent(name="foo") - self.assertEqual(ret["result"], True) - self.assertEqual(ret["comment"], "Value for grain foo was set to None") - self.assertEqual(ret["changes"], {"grain": "foo", "value": None}) - self.assertEqual(grains.__grains__, {"a": "aval", "foo": None}) - self.assertGrainFileContent("a: aval\n" + "foo: null\n") - - # Unset grain when its value is False - with self.setGrains({"a": "aval", "foo": False}): - ret = grains.absent(name="foo") - self.assertEqual(ret["result"], True) - self.assertEqual(ret["comment"], "Value for grain foo was set to None") - self.assertEqual(ret["changes"], {"grain": "foo", "value": None}) - self.assertEqual(grains.__grains__, {"a": "aval", "foo": None}) - self.assertGrainFileContent("a: aval\n" + "foo: null\n") - - # Unset a nested grain - with self.setGrains( - {"a": "aval", "foo": ["order", {"is": {"nested": "bar"}}, "correct"]} - ): - ret = grains.absent(name="foo,is,nested", delimiter=",") - self.assertEqual(ret["result"], True) - self.assertEqual( - ret["comment"], "Value for grain foo:is:nested was set to None" - ) - self.assertEqual(ret["changes"], {"grain": "foo:is:nested", "value": None}) - self.assertEqual( - grains.__grains__, - {"a": "aval", "foo": ["order", {"is": {"nested": None}}, "correct"]}, - ) - self.assertGrainFileContent( - "a: aval\n" - + "foo:\n" - + "- order\n" - + "- is:\n" - + " nested: null\n" - + "- correct\n" - ) - - # Unset a nested value don't change anything - with self.setGrains( - {"a": "aval", "foo": ["order", {"is": "nested"}, "correct"]} - ): - ret = grains.absent(name="foo:is:nested") - self.assertEqual(ret["result"], True) - self.assertEqual(ret["comment"], "Grain foo:is:nested does not exist") - self.assertEqual(ret["changes"], {}) - self.assertEqual( - grains.__grains__, - {"a": "aval", "foo": ["order", {"is": "nested"}, "correct"]}, - ) - self.assertGrainFileContent( - "a: aval\n" + "foo:\n" + "- order\n" + "- is: nested\n" + "- correct\n" - ) - - def test_absent_unset_test(self): - with patch.dict(grains.__opts__, {"test": True}): - with self.setGrains({"a": "aval", "foo": "bar"}): - # Overwrite an existing grain - ret = grains.absent(name="foo") - self.assertEqual(ret["result"], None) - self.assertEqual(ret["changes"], {"grain": "foo", "value": None}) - self.assertEqual(grains.__grains__, {"a": "aval", "foo": "bar"}) - self.assertGrainFileContent("a: aval\n" + "foo: bar\n") - - def test_absent_fails_nested_complex_grain(self): - # Unset a nested complex grain - with self.setGrains( - {"a": "aval", "foo": ["order", {"is": {"nested": "bar"}}, "correct"]} - ): - ret = grains.absent(name="foo:is") - self.assertEqual(ret["result"], False) - self.assertEqual( - ret["comment"], - "The key 'foo:is' exists but is a dict or a list. Use 'force=True' to" - " overwrite.", - ) - self.assertEqual(ret["changes"], {}) - self.assertEqual( - grains.__grains__, - {"a": "aval", "foo": ["order", {"is": {"nested": "bar"}}, "correct"]}, - ) - self.assertGrainFileContent( - "a: aval\n" - + "foo:\n" - + "- order\n" - + "- is:\n" - + " nested: bar\n" - + "- correct\n" - ) - - def test_absent_force_nested_complex_grain(self): - # Unset a nested complex grain - with self.setGrains( - {"a": "aval", "foo": ["order", {"is": {"nested": "bar"}}, "correct"]} - ): - ret = grains.absent(name="foo:is", force=True) - self.assertEqual(ret["result"], True) - self.assertEqual(ret["comment"], "Value for grain foo:is was set to None") - self.assertEqual(ret["changes"], {"grain": "foo:is", "value": None}) - self.assertEqual( - grains.__grains__, - {"a": "aval", "foo": ["order", {"is": None}, "correct"]}, - ) - self.assertGrainFileContent( - "a: aval\n" + "foo:\n" + "- order\n" + "- is: null\n" + "- correct\n" - ) - - def test_absent_delete(self): - # Delete a grain - with self.setGrains({"a": "aval", "foo": "bar"}): - ret = grains.absent(name="foo", destructive=True) - self.assertEqual(ret["result"], True) - self.assertEqual(ret["comment"], "Grain foo was deleted") - self.assertEqual(ret["changes"], {"deleted": "foo"}) - self.assertEqual(grains.__grains__, {"a": "aval"}) - self.assertGrainFileContent("a: aval\n") - - # Delete a previously unset grain - with self.setGrains({"a": "aval", "foo": None}): - ret = grains.absent(name="foo", destructive=True) - self.assertEqual(ret["result"], True) - self.assertEqual(ret["comment"], "Grain foo was deleted") - self.assertEqual(ret["changes"], {"deleted": "foo"}) - self.assertEqual(grains.__grains__, {"a": "aval"}) - self.assertGrainFileContent("a: aval\n") - - # Delete a nested grain - with self.setGrains( - { - "a": "aval", - "foo": [ - "order", - {"is": {"nested": "bar", "other": "value"}}, - "correct", - ], - } - ): - ret = grains.absent(name="foo:is:nested", destructive=True) - self.assertEqual(ret["result"], True) - self.assertEqual(ret["comment"], "Grain foo:is:nested was deleted") - self.assertEqual(ret["changes"], {"deleted": "foo:is:nested"}) - self.assertEqual( - grains.__grains__, - {"a": "aval", "foo": ["order", {"is": {"other": "value"}}, "correct"]}, - ) - self.assertGrainFileContent( - "a: aval\n" - + "foo:\n" - + "- order\n" - + "- is:\n" - + " other: value\n" - + "- correct\n" - ) - - # 'append' function tests: 6 - - def test_append(self): - # Append to an existing list - with self.setGrains({"a": "aval", "foo": ["bar"]}): - ret = grains.append(name="foo", value="baz") - self.assertEqual(ret["result"], True) - self.assertEqual(ret["comment"], "Value baz was added to grain foo") - self.assertEqual(ret["changes"], {"added": "baz"}) - self.assertEqual(grains.__grains__, {"a": "aval", "foo": ["bar", "baz"]}) - self.assertGrainFileContent("a: aval\n" + "foo:\n" + "- bar\n" + "- baz\n") - - def test_append_nested(self): - # Append to an existing nested list - with self.setGrains({"a": "aval", "foo": {"list": ["bar"]}}): - ret = grains.append(name="foo,list", value="baz", delimiter=",") - self.assertEqual(ret["result"], True) - self.assertEqual(ret["comment"], "Value baz was added to grain foo:list") - self.assertEqual(ret["changes"], {"added": "baz"}) - self.assertEqual( - grains.__grains__, {"a": "aval", "foo": {"list": ["bar", "baz"]}} - ) - self.assertGrainFileContent( - "a: aval\n" + "foo:\n" + " list:\n" + " - bar\n" + " - baz\n" - ) - - def test_append_already(self): - # Append to an existing list - with self.setGrains({"a": "aval", "foo": ["bar"]}): - ret = grains.append(name="foo", value="bar") - self.assertEqual(ret["result"], True) - self.assertEqual( - ret["comment"], "Value bar is already in the list " + "for grain foo" - ) - self.assertEqual(ret["changes"], {}) - self.assertEqual(grains.__grains__, {"a": "aval", "foo": ["bar"]}) - self.assertGrainFileContent("a: aval\n" + "foo:\n" + "- bar\n") - - def test_append_fails_not_a_list(self): - # Fail to append to an existing grain, not a list - with self.setGrains({"a": "aval", "foo": {"bar": "val"}}): - ret = grains.append(name="foo", value="baz") - self.assertEqual(ret["result"], False) - self.assertEqual(ret["comment"], "Grain foo is not a valid list") - self.assertEqual(ret["changes"], {}) - self.assertEqual(grains.__grains__, {"a": "aval", "foo": {"bar": "val"}}) - - def test_append_convert_to_list(self): - # Append to an existing grain, converting to a list - with self.setGrains({"a": "aval", "foo": {"bar": "val"}}): - self.assertGrainFileContent("a: aval\n" + "foo:\n" + " bar: val\n") - ret = grains.append(name="foo", value="baz", convert=True) - self.assertEqual(ret["result"], True) - self.assertEqual(ret["comment"], "Value baz was added to grain foo") - self.assertEqual(ret["changes"], {"added": "baz"}) - self.assertEqual( - grains.__grains__, {"a": "aval", "foo": [{"bar": "val"}, "baz"]} - ) - self.assertGrainFileContent( - "a: aval\n" + "foo:\n" + "- bar: val\n" + "- baz\n" - ) - - # Append to an existing grain, converting to a list a multi-value dict - with self.setGrains({"a": "aval", "foo": {"bar": "val", "other": "value"}}): - self.assertGrainFileContent( - "a: aval\n" + "foo:\n" + " bar: val\n" + " other: value\n" - ) - ret = grains.append(name="foo", value="baz", convert=True) - self.assertEqual(ret["result"], True) - self.assertEqual(ret["comment"], "Value baz was added to grain foo") - self.assertEqual(ret["changes"], {"added": "baz"}) - self.assertEqual( - grains.__grains__, - {"a": "aval", "foo": [{"bar": "val", "other": "value"}, "baz"]}, - ) - self.assertGrainFileContent( - "a: aval\n" + "foo:\n" + "- bar: val\n" + " other: value\n" + "- baz\n" - ) - - def test_append_fails_inexistent(self): - # Append to a non existing grain - with self.setGrains({"a": "aval"}): - ret = grains.append(name="foo", value="bar") - self.assertEqual(ret["result"], False) - self.assertEqual(ret["comment"], "Grain foo does not exist") - self.assertEqual(ret["changes"], {}) - self.assertEqual(grains.__grains__, {"a": "aval"}) - - def test_append_convert_to_list_empty(self): - # Append to an existing list - with self.setGrains({"foo": None}): - ret = grains.append(name="foo", value="baz", convert=True) - self.assertEqual(ret["result"], True) - self.assertEqual(ret["comment"], "Value baz was added to grain foo") - self.assertEqual(ret["changes"], {"added": "baz"}) - self.assertEqual(grains.__grains__, {"foo": ["baz"]}) - self.assertGrainFileContent("foo:\n" + "- baz\n") - - # 'list_present' function tests: 7 - - def test_list_present(self): - with self.setGrains({"a": "aval", "foo": ["bar"]}): - ret = grains.list_present(name="foo", value="baz") - self.assertEqual(ret["result"], True) - self.assertEqual(ret["comment"], "Append value baz to grain foo") - self.assertEqual(ret["changes"], {"new": {"foo": ["bar", "baz"]}}) - self.assertEqual(grains.__grains__, {"a": "aval", "foo": ["bar", "baz"]}) - self.assertGrainFileContent("a: aval\n" + "foo:\n" + "- bar\n" + "- baz\n") - - def test_list_present_nested(self): - with self.setGrains({"a": "aval", "foo": {"is": {"nested": ["bar"]}}}): - ret = grains.list_present(name="foo,is,nested", value="baz", delimiter=",") - self.assertEqual(ret["result"], True) - self.assertEqual(ret["comment"], "Append value baz to grain foo:is:nested") - self.assertEqual( - ret["changes"], {"new": {"foo": {"is": {"nested": ["bar", "baz"]}}}} - ) - self.assertEqual( - grains.__grains__, - {"a": "aval", "foo": {"is": {"nested": ["bar", "baz"]}}}, - ) - self.assertGrainFileContent( - "a: aval\n" - + "foo:\n" - + " is:\n" - + " nested:\n" - + " - bar\n" - + " - baz\n" - ) - - def test_list_present_inexistent(self): - with self.setGrains({"a": "aval"}): - ret = grains.list_present(name="foo", value="baz") - self.assertEqual(ret["result"], True) - self.assertEqual(ret["comment"], "Append value baz to grain foo") - self.assertEqual(ret["changes"], {"new": {"foo": ["baz"]}}) - self.assertEqual(grains.__grains__, {"a": "aval", "foo": ["baz"]}) - self.assertGrainFileContent("a: aval\n" + "foo:\n" + "- baz\n") - - def test_list_present_inexistent_nested(self): - with self.setGrains({"a": "aval"}): - ret = grains.list_present(name="foo:is:nested", value="baz") - self.assertEqual(ret["result"], True) - self.assertEqual(ret["comment"], "Append value baz to grain foo:is:nested") - self.assertEqual( - ret["changes"], {"new": {"foo": {"is": {"nested": ["baz"]}}}} - ) - self.assertEqual( - grains.__grains__, {"a": "aval", "foo": {"is": {"nested": ["baz"]}}} - ) - self.assertGrainFileContent( - "a: aval\n" + "foo:\n" + " is:\n" + " nested:\n" + " - baz\n" - ) - - def test_list_present_not_a_list(self): - with self.setGrains({"a": "aval", "foo": "bar"}): - ret = grains.list_present(name="foo", value="baz") - self.assertEqual(ret["result"], False) - self.assertEqual(ret["comment"], "Grain foo is not a valid list") - self.assertEqual(ret["changes"], {}) - self.assertEqual(grains.__grains__, {"a": "aval", "foo": "bar"}) - self.assertGrainFileContent("a: aval\n" + "foo: bar\n") - - def test_list_present_nested_already(self): - with self.setGrains({"a": "aval", "b": {"foo": ["bar"]}}): - ret = grains.list_present(name="b:foo", value="bar") - self.assertEqual(ret["result"], True) - self.assertEqual(ret["comment"], "Value bar is already in grain b:foo") - self.assertEqual(ret["changes"], {}) - self.assertEqual(grains.__grains__, {"a": "aval", "b": {"foo": ["bar"]}}) - self.assertGrainFileContent("a: aval\n" + "b:\n" + " foo:\n" + " - bar\n") - - def test_list_present_already(self): - with self.setGrains({"a": "aval", "foo": ["bar"]}): - ret = grains.list_present(name="foo", value="bar") - self.assertEqual(ret["result"], True) - self.assertEqual(ret["comment"], "Value bar is already in grain foo") - self.assertEqual(ret["changes"], {}) - self.assertEqual(grains.__grains__, {"a": "aval", "foo": ["bar"]}) - self.assertGrainFileContent("a: aval\n" + "foo:\n" + "- bar\n") - - def test_list_present_unknown_failure(self): - with self.setGrains({"a": "aval", "foo": ["bar"]}): - # Unknown reason failure - - with patch.dict(grainsmod.__salt__, {"grains.append": MagicMock()}): - ret = grains.list_present(name="foo", value="baz") - self.assertEqual(ret["result"], False) - self.assertEqual(ret["comment"], "Failed append value baz to grain foo") - self.assertEqual(ret["changes"], {}) - self.assertEqual(grains.__grains__, {"a": "aval", "foo": ["bar"]}) - self.assertGrainFileContent("a: aval\n" + "foo:\n" + "- bar\n") - - # 'list_absent' function tests: 6 - - def test_list_absent(self): - with self.setGrains({"a": "aval", "foo": ["bar"]}): - ret = grains.list_absent(name="foo", value="bar") - self.assertEqual(ret["result"], True) - self.assertEqual(ret["comment"], "Value bar was deleted from grain foo") - self.assertEqual(ret["changes"], {"deleted": ["bar"]}) - self.assertEqual(grains.__grains__, {"a": "aval", "foo": []}) - self.assertGrainFileContent("a: aval\n" + "foo: []\n") - - def test_list_absent_nested(self): - with self.setGrains({"a": "aval", "foo": {"list": ["bar"]}}): - ret = grains.list_absent(name="foo:list", value="bar") - self.assertEqual(ret["result"], True) - self.assertEqual( - ret["comment"], "Value bar was deleted from grain foo:list" - ) - self.assertEqual(ret["changes"], {"deleted": ["bar"]}) - self.assertEqual(grains.__grains__, {"a": "aval", "foo": {"list": []}}) - self.assertGrainFileContent("a: aval\n" + "foo:\n" + " list: []\n") - - def test_list_absent_inexistent(self): - with self.setGrains({"a": "aval"}): - ret = grains.list_absent(name="foo", value="baz") - self.assertEqual(ret["result"], True) - self.assertEqual(ret["comment"], "Grain foo does not exist") - self.assertEqual(ret["changes"], {}) - self.assertEqual(grains.__grains__, {"a": "aval"}) - self.assertGrainFileContent("a: aval\n") - - def test_list_absent_inexistent_nested(self): - with self.setGrains({"a": "aval"}): - ret = grains.list_absent(name="foo:list", value="baz") - self.assertEqual(ret["result"], True) - self.assertEqual(ret["comment"], "Grain foo:list does not exist") - self.assertEqual(ret["changes"], {}) - self.assertEqual(grains.__grains__, {"a": "aval"}) - self.assertGrainFileContent("a: aval\n") - - def test_list_absent_not_a_list(self): - with self.setGrains({"a": "aval", "foo": "bar"}): - ret = grains.list_absent(name="foo", value="bar") - self.assertEqual(ret["result"], False) - self.assertEqual(ret["comment"], "Grain foo is not a valid list") - self.assertEqual(ret["changes"], {}) - self.assertEqual(grains.__grains__, {"a": "aval", "foo": "bar"}) - self.assertGrainFileContent("a: aval\n" + "foo: bar\n") - - def test_list_absent_already(self): - with self.setGrains({"a": "aval", "foo": ["bar"]}): - ret = grains.list_absent(name="foo", value="baz") - self.assertEqual(ret["result"], True) - self.assertEqual(ret["comment"], "Value baz is absent from grain foo") - self.assertEqual(ret["changes"], {}) - self.assertEqual(grains.__grains__, {"a": "aval", "foo": ["bar"]}) - self.assertGrainFileContent("a: aval\n" + "foo:\n" + "- bar\n") From ba208bbae2080ad5486a47733f9246331cf5b327 Mon Sep 17 00:00:00 2001 From: Frode Gundersen Date: Wed, 12 Apr 2023 10:38:58 -0600 Subject: [PATCH 07/11] Update test_grains.py --- tests/pytests/unit/states/test_grains.py | 151 +++++++---------------- 1 file changed, 45 insertions(+), 106 deletions(-) diff --git a/tests/pytests/unit/states/test_grains.py b/tests/pytests/unit/states/test_grains.py index 43f2afd9df5..99a76a4357f 100644 --- a/tests/pytests/unit/states/test_grains.py +++ b/tests/pytests/unit/states/test_grains.py @@ -97,11 +97,8 @@ def test_exists_found(): def test_make_hashable(): with setGrains({"cmplx_lst_grain": [{"a": "aval"}, {"foo": "bar"}]}): hashable_list = {"cmplx_lst_grain": [{"a": "aval"}, {"foo": "bar"}]} - assert ( - grains.make_hashable(grains.__grains__).issubset( - grains.make_hashable(hashable_list) - ) - is True + assert grains.make_hashable(grains.__grains__).issubset( + grains.make_hashable(hashable_list) ) # 'present' function tests: 12 @@ -134,11 +131,7 @@ def test_present_add(): "foo": {"is": {"nested": {"bar": "is a dict"}}}, } assertGrainFileContent( - "a: aval\n" - + "foo:\n" - + " is:\n" - + " nested:\n" - + " bar: is a dict\n" + "a: aval\nfoo:\n is:\n nested:\n bar: is a dict\n" ) @@ -150,7 +143,7 @@ def test_present_add_key_to_existing(): assert ret["comment"] == "Set grain foo:k2 to v2" assert ret["changes"] == {"foo": {"k2": "v2", "k1": "v1"}} assert grains.__grains__ == {"a": "aval", "foo": {"k1": "v1", "k2": "v2"}} - assertGrainFileContent("a: aval\n" + "foo:\n" + " k1: v1\n" + " k2: v2\n") + assertGrainFileContent("a: aval\nfoo:\n k1: v1\n k2: v2\n") def test_present_already_set(): @@ -186,7 +179,7 @@ def test_present_overwrite(): assert ret["result"] is True assert ret["changes"] == {"foo": "newbar"} assert grains.__grains__ == {"a": "aval", "foo": "newbar"} - assertGrainFileContent("a: aval\n" + "foo: newbar\n") + assertGrainFileContent("a: aval\nfoo: newbar\n") with setGrains({"a": "aval", "foo": "bar"}): # Clear a grain (set to None) @@ -194,7 +187,7 @@ def test_present_overwrite(): assert ret["result"] is True assert ret["changes"] == {"foo": None} assert grains.__grains__ == {"a": "aval", "foo": None} - assertGrainFileContent("a: aval\n" + "foo: null\n") + assertGrainFileContent("a: aval\nfoo: null\n") with setGrains({"a": "aval", "foo": {"is": {"nested": "bar"}}}): # Overwrite an existing nested grain @@ -202,9 +195,7 @@ def test_present_overwrite(): assert ret["result"] is True assert ret["changes"] == {"foo": {"is": {"nested": "newbar"}}} assert grains.__grains__ == {"a": "aval", "foo": {"is": {"nested": "newbar"}}} - assertGrainFileContent( - "a: aval\n" + "foo:\n" + " is:\n" + " nested: newbar\n" - ) + assertGrainFileContent("a: aval\nfoo:\n is:\n nested: newbar\n") with setGrains({"a": "aval", "foo": {"is": {"nested": "bar"}}}): # Clear a nested grain (set to None) @@ -212,9 +203,7 @@ def test_present_overwrite(): assert ret["result"] is True assert ret["changes"] == {"foo": {"is": {"nested": None}}} assert grains.__grains__ == {"a": "aval", "foo": {"is": {"nested": None}}} - assertGrainFileContent( - "a: aval\n" + "foo:\n" + " is:\n" + " nested: null\n" - ) + assertGrainFileContent("a: aval\nfoo:\n is:\n nested: null\n") def test_present_fail_overwrite(): @@ -297,7 +286,7 @@ def test_present_fail_merge_dict(): == "The key 'foo' exists but is a dict or a list. Use 'force=True' to overwrite." ) assert grains.__grains__ == {"a": "aval", "foo": {"k1": "v1"}} - assertGrainFileContent("a: aval\n" + "foo:\n" + " k1: v1\n") + assertGrainFileContent("a: aval\nfoo:\n k1: v1\n") def test_present_force_to_set_dict_or_list(): @@ -308,7 +297,7 @@ def test_present_force_to_set_dict_or_list(): assert ret["comment"] == "Set grain foo to ['l1', 'l2']" assert ret["changes"] == {"foo": ["l1", "l2"]} assert grains.__grains__ == {"a": "aval", "foo": ["l1", "l2"]} - assertGrainFileContent("a: aval\n" + "foo:\n" + "- l1\n" + "- l2\n") + assertGrainFileContent("a: aval\nfoo:\n- l1\n- l2\n") with setGrains({"a": "aval", "foo": "bar"}): # Force setting a grain to a dict @@ -317,7 +306,7 @@ def test_present_force_to_set_dict_or_list(): assert ret["comment"] == "Set grain foo to {'k1': 'v1'}" assert ret["changes"] == {"foo": {"k1": "v1"}} assert grains.__grains__ == {"a": "aval", "foo": {"k1": "v1"}} - assertGrainFileContent("a: aval\n" + "foo:\n" + " k1: v1\n") + assertGrainFileContent("a: aval\nfoo:\n k1: v1\n") with setGrains({"a": "aval", "foo": {"is": {"nested": "bar"}}}): # Force to overwrite a nested grain to a list @@ -332,12 +321,7 @@ def test_present_force_to_set_dict_or_list(): "foo": {"is": {"nested": ["l1", "l2"]}}, } assertGrainFileContent( - "a: aval\n" - + "foo:\n" - + " is:\n" - + " nested:\n" - + " - l1\n" - + " - l2\n" + "a: aval\nfoo:\n is:\n nested:\n - l1\n - l2\n" ) with setGrains({"a": "aval", "foo": {"is": {"nested": "bar"}, "and": "other"}}): @@ -353,12 +337,7 @@ def test_present_force_to_set_dict_or_list(): "foo": {"is": {"nested": {"k1": "v1"}}, "and": "other"}, } assertGrainFileContent( - "a: aval\n" - + "foo:\n" - + " and: other\n" - + " is:\n" - + " nested:\n" - + " k1: v1\n" + "a: aval\nfoo:\n and: other\n is:\n nested:\n k1: v1\n" ) @@ -382,7 +361,7 @@ def test_present_overwrite_test(): assert ret["result"] is None assert ret["changes"] == {"changed": {"foo": "newbar"}} assert grains.__grains__ == {"a": "aval", "foo": "bar"} - assertGrainFileContent("a: aval\n" + "foo: bar\n") + assertGrainFileContent("a: aval\nfoo: bar\n") def test_present_convert_value_to_key(): @@ -396,9 +375,7 @@ def test_present_convert_value_to_key(): "a": "aval", "foo": {"is": {"nested": {"k1": "v1"}}}, } - assertGrainFileContent( - "a: aval\n" + "foo:\n" + " is:\n" + " nested:\n" + " k1: v1\n" - ) + assertGrainFileContent("a: aval\nfoo:\n is:\n nested:\n k1: v1\n") with setGrains({"a": "aval", "foo": ["one", "is", "correct"]}): # Converts a list element to a nested grain key @@ -413,13 +390,7 @@ def test_present_convert_value_to_key(): "foo": ["one", {"is": {"nested": {"k1": "v1"}}}, "correct"], } assertGrainFileContent( - "a: aval\n" - + "foo:\n" - + "- one\n" - + "- is:\n" - + " nested:\n" - + " k1: v1\n" - + "- correct\n" + "a: aval\nfoo:\n- one\n- is:\n nested:\n k1: v1\n- correct\n" ) @@ -433,7 +404,7 @@ def test_present_unknown_failure(): assert ret["comment"] == "Failed to set grain foo" assert ret["changes"] == {} assert grains.__grains__ == {"a": "aval", "foo": "bar"} - assertGrainFileContent("a: aval\n" + "foo: bar\n") + assertGrainFileContent("a: aval\nfoo: bar\n") # 'absent' function tests: 6 @@ -467,7 +438,7 @@ def test_absent_unset(): assert ret["comment"] == "Value for grain foo was set to None" assert ret["changes"] == {"grain": "foo", "value": None} assert grains.__grains__ == {"a": "aval", "foo": None} - assertGrainFileContent("a: aval\n" + "foo: null\n") + assertGrainFileContent("a: aval\nfoo: null\n") # Unset grain when its value is False with setGrains({"a": "aval", "foo": False}): @@ -476,7 +447,7 @@ def test_absent_unset(): assert ret["comment"] == "Value for grain foo was set to None" assert ret["changes"] == {"grain": "foo", "value": None} assert grains.__grains__ == {"a": "aval", "foo": None} - assertGrainFileContent("a: aval\n" + "foo: null\n") + assertGrainFileContent("a: aval\nfoo: null\n") # Unset a nested grain with setGrains( @@ -491,12 +462,7 @@ def test_absent_unset(): "foo": ["order", {"is": {"nested": None}}, "correct"], } assertGrainFileContent( - "a: aval\n" - + "foo:\n" - + "- order\n" - + "- is:\n" - + " nested: null\n" - + "- correct\n" + "a: aval\nfoo:\n- order\n- is:\n nested: null\n- correct\n" ) # Unset a nested value don't change anything @@ -509,9 +475,7 @@ def test_absent_unset(): "a": "aval", "foo": ["order", {"is": "nested"}, "correct"], } - assertGrainFileContent( - "a: aval\n" + "foo:\n" + "- order\n" + "- is: nested\n" + "- correct\n" - ) + assertGrainFileContent("a: aval\nfoo:\n- order\n- is: nested\n- correct\n") def test_absent_unset_test(): @@ -522,7 +486,7 @@ def test_absent_unset_test(): assert ret["result"] is None assert ret["changes"] == {"grain": "foo", "value": None} assert grains.__grains__ == {"a": "aval", "foo": "bar"} - assertGrainFileContent("a: aval\n" + "foo: bar\n") + assertGrainFileContent("a: aval\nfoo: bar\n") def test_absent_fails_nested_complex_grain(): @@ -542,12 +506,7 @@ def test_absent_fails_nested_complex_grain(): "foo": ["order", {"is": {"nested": "bar"}}, "correct"], } assertGrainFileContent( - "a: aval\n" - + "foo:\n" - + "- order\n" - + "- is:\n" - + " nested: bar\n" - + "- correct\n" + "a: aval\nfoo:\n- order\n- is:\n nested: bar\n- correct\n" ) @@ -564,9 +523,7 @@ def test_absent_force_nested_complex_grain(): "a": "aval", "foo": ["order", {"is": None}, "correct"], } - assertGrainFileContent( - "a: aval\n" + "foo:\n" + "- order\n" + "- is: null\n" + "- correct\n" - ) + assertGrainFileContent("a: aval\nfoo:\n- order\n- is: null\n- correct\n") def test_absent_delete(): @@ -608,12 +565,7 @@ def test_absent_delete(): "foo": ["order", {"is": {"other": "value"}}, "correct"], } assertGrainFileContent( - "a: aval\n" - + "foo:\n" - + "- order\n" - + "- is:\n" - + " other: value\n" - + "- correct\n" + "a: aval\nfoo:\n- order\n- is:\n other: value\n- correct\n" ) @@ -628,7 +580,7 @@ def test_append(): assert ret["comment"] == "Value baz was added to grain foo" assert ret["changes"] == {"added": "baz"} assert grains.__grains__ == {"a": "aval", "foo": ["bar", "baz"]} - assertGrainFileContent("a: aval\n" + "foo:\n" + "- bar\n" + "- baz\n") + assertGrainFileContent("a: aval\nfoo:\n- bar\n- baz\n") def test_append_nested(): @@ -639,9 +591,7 @@ def test_append_nested(): assert ret["comment"] == "Value baz was added to grain foo:list" assert ret["changes"] == {"added": "baz"} assert grains.__grains__ == {"a": "aval", "foo": {"list": ["bar", "baz"]}} - assertGrainFileContent( - "a: aval\n" + "foo:\n" + " list:\n" + " - bar\n" + " - baz\n" - ) + assertGrainFileContent("a: aval\nfoo:\n list:\n - bar\n - baz\n") def test_append_already(): @@ -652,7 +602,7 @@ def test_append_already(): assert ret["comment"] == "Value bar is already in the list " + "for grain foo" assert ret["changes"] == {} assert grains.__grains__ == {"a": "aval", "foo": ["bar"]} - assertGrainFileContent("a: aval\n" + "foo:\n" + "- bar\n") + assertGrainFileContent("a: aval\nfoo:\n- bar\n") def test_append_fails_not_a_list(): @@ -668,19 +618,17 @@ def test_append_fails_not_a_list(): def test_append_convert_to_list(): # Append to an existing grain, converting to a list with setGrains({"a": "aval", "foo": {"bar": "val"}}): - assertGrainFileContent("a: aval\n" + "foo:\n" + " bar: val\n") + assertGrainFileContent("a: aval\nfoo:\n bar: val\n") ret = grains.append(name="foo", value="baz", convert=True) assert ret["result"] is True assert ret["comment"] == "Value baz was added to grain foo" assert ret["changes"] == {"added": "baz"} assert grains.__grains__ == {"a": "aval", "foo": [{"bar": "val"}, "baz"]} - assertGrainFileContent("a: aval\n" + "foo:\n" + "- bar: val\n" + "- baz\n") + assertGrainFileContent("a: aval\nfoo:\n- bar: val\n- baz\n") # Append to an existing grain, converting to a list a multi-value dict with setGrains({"a": "aval", "foo": {"bar": "val", "other": "value"}}): - assertGrainFileContent( - "a: aval\n" + "foo:\n" + " bar: val\n" + " other: value\n" - ) + assertGrainFileContent("a: aval\nfoo:\n bar: val\n other: value\n") ret = grains.append(name="foo", value="baz", convert=True) assert ret["result"] is True assert ret["comment"] == "Value baz was added to grain foo" @@ -689,9 +637,7 @@ def test_append_convert_to_list(): "a": "aval", "foo": [{"bar": "val", "other": "value"}, "baz"], } - assertGrainFileContent( - "a: aval\n" + "foo:\n" + "- bar: val\n" + " other: value\n" + "- baz\n" - ) + assertGrainFileContent("a: aval\nfoo:\n- bar: val\n other: value\n- baz\n") def test_append_fails_inexistent(): @@ -712,7 +658,7 @@ def test_append_convert_to_list_empty(): assert ret["comment"] == "Value baz was added to grain foo" assert ret["changes"] == {"added": "baz"} assert grains.__grains__ == {"foo": ["baz"]} - assertGrainFileContent("foo:\n" + "- baz\n") + assertGrainFileContent("foo:\n- baz\n") # 'list_present' function tests: 7 @@ -725,7 +671,7 @@ def test_list_present(): assert ret["comment"] == "Append value baz to grain foo" assert ret["changes"] == {"new": {"foo": ["bar", "baz"]}} assert grains.__grains__ == {"a": "aval", "foo": ["bar", "baz"]} - assertGrainFileContent("a: aval\n" + "foo:\n" + "- bar\n" + "- baz\n") + assertGrainFileContent("a: aval\nfoo:\n- bar\n- baz\n") def test_list_present_nested(): @@ -739,12 +685,7 @@ def test_list_present_nested(): "foo": {"is": {"nested": ["bar", "baz"]}}, } assertGrainFileContent( - "a: aval\n" - + "foo:\n" - + " is:\n" - + " nested:\n" - + " - bar\n" - + " - baz\n" + "a: aval\nfoo:\n is:\n nested:\n - bar\n - baz\n" ) @@ -755,7 +696,7 @@ def test_list_present_inexistent(): assert ret["comment"] == "Append value baz to grain foo" assert ret["changes"] == {"new": {"foo": ["baz"]}} assert grains.__grains__ == {"a": "aval", "foo": ["baz"]} - assertGrainFileContent("a: aval\n" + "foo:\n" + "- baz\n") + assertGrainFileContent("a: aval\nfoo:\n- baz\n") def test_list_present_inexistent_nested(): @@ -765,9 +706,7 @@ def test_list_present_inexistent_nested(): assert ret["comment"] == "Append value baz to grain foo:is:nested" assert ret["changes"] == {"new": {"foo": {"is": {"nested": ["baz"]}}}} assert grains.__grains__ == {"a": "aval", "foo": {"is": {"nested": ["baz"]}}} - assertGrainFileContent( - "a: aval\n" + "foo:\n" + " is:\n" + " nested:\n" + " - baz\n" - ) + assertGrainFileContent("a: aval\nfoo:\n is:\n nested:\n - baz\n") def test_list_present_not_a_list(): @@ -777,7 +716,7 @@ def test_list_present_not_a_list(): assert ret["comment"] == "Grain foo is not a valid list" assert ret["changes"] == {} assert grains.__grains__ == {"a": "aval", "foo": "bar"} - assertGrainFileContent("a: aval\n" + "foo: bar\n") + assertGrainFileContent("a: aval\nfoo: bar\n") def test_list_present_nested_already(): @@ -787,7 +726,7 @@ def test_list_present_nested_already(): assert ret["comment"] == "Value bar is already in grain b:foo" assert ret["changes"] == {} assert grains.__grains__ == {"a": "aval", "b": {"foo": ["bar"]}} - assertGrainFileContent("a: aval\n" + "b:\n" + " foo:\n" + " - bar\n") + assertGrainFileContent("a: aval\nb:\n foo:\n - bar\n") def test_list_present_already(): @@ -797,7 +736,7 @@ def test_list_present_already(): assert ret["comment"] == "Value bar is already in grain foo" assert ret["changes"] == {} assert grains.__grains__ == {"a": "aval", "foo": ["bar"]} - assertGrainFileContent("a: aval\n" + "foo:\n" + "- bar\n") + assertGrainFileContent("a: aval\nfoo:\n- bar\n") def test_list_present_unknown_failure(): @@ -810,7 +749,7 @@ def test_list_present_unknown_failure(): assert ret["comment"] == "Failed append value baz to grain foo" assert ret["changes"] == {} assert grains.__grains__ == {"a": "aval", "foo": ["bar"]} - assertGrainFileContent("a: aval\n" + "foo:\n" + "- bar\n") + assertGrainFileContent("a: aval\nfoo:\n- bar\n") # 'list_absent' function tests: 6 @@ -823,7 +762,7 @@ def test_list_absent(): assert ret["comment"] == "Value bar was deleted from grain foo" assert ret["changes"] == {"deleted": ["bar"]} assert grains.__grains__ == {"a": "aval", "foo": []} - assertGrainFileContent("a: aval\n" + "foo: []\n") + assertGrainFileContent("a: aval\nfoo: []\n") def test_list_absent_nested(): @@ -833,7 +772,7 @@ def test_list_absent_nested(): assert ret["comment"] == "Value bar was deleted from grain foo:list" assert ret["changes"] == {"deleted": ["bar"]} assert grains.__grains__ == {"a": "aval", "foo": {"list": []}} - assertGrainFileContent("a: aval\n" + "foo:\n" + " list: []\n") + assertGrainFileContent("a: aval\nfoo:\n list: []\n") def test_list_absent_inexistent(): @@ -863,7 +802,7 @@ def test_list_absent_not_a_list(): assert ret["comment"] == "Grain foo is not a valid list" assert ret["changes"] == {} assert grains.__grains__ == {"a": "aval", "foo": "bar"} - assertGrainFileContent("a: aval\n" + "foo: bar\n") + assertGrainFileContent("a: aval\nfoo: bar\n") def test_list_absent_already(): @@ -873,4 +812,4 @@ def test_list_absent_already(): assert ret["comment"] == "Value baz is absent from grain foo" assert ret["changes"] == {} assert grains.__grains__ == {"a": "aval", "foo": ["bar"]} - assertGrainFileContent("a: aval\n" + "foo:\n" + "- bar\n") + assertGrainFileContent("a: aval\nfoo:\n- bar\n") From 89e2bba635c4fe2dac06642292cc6d9959961b91 Mon Sep 17 00:00:00 2001 From: Pedro Algarvio Date: Wed, 13 Dec 2023 05:28:12 +0000 Subject: [PATCH 08/11] Set the right path for the config file Signed-off-by: Pedro Algarvio --- tests/pytests/unit/conftest.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/pytests/unit/conftest.py b/tests/pytests/unit/conftest.py index 587fc43babc..c7152f3d2d1 100644 --- a/tests/pytests/unit/conftest.py +++ b/tests/pytests/unit/conftest.py @@ -1,3 +1,5 @@ +import os + import pytest import salt.config @@ -20,6 +22,7 @@ def minion_opts(tmp_path): dirpath.mkdir(parents=True) opts[name] = str(dirpath) opts["log_file"] = "logs/minion.log" + opts["conf_file"] = os.path.join(opts["conf_dir"], "minion") return opts @@ -37,6 +40,7 @@ def master_opts(tmp_path): dirpath.mkdir(parents=True) opts[name] = str(dirpath) opts["log_file"] = "logs/master.log" + opts["conf_file"] = os.path.join(opts["conf_dir"], "master") return opts @@ -55,4 +59,5 @@ def syndic_opts(tmp_path): dirpath.mkdir(parents=True) opts[name] = str(dirpath) opts["log_file"] = "logs/syndic.log" + opts["conf_file"] = os.path.join(opts["conf_dir"], "syndic") return opts From 6d3a4710cb353a9d1477bc09eb58530cb57d1fbe Mon Sep 17 00:00:00 2001 From: Pedro Algarvio Date: Wed, 13 Dec 2023 05:32:18 +0000 Subject: [PATCH 09/11] Fix the ``configure_loader_modules`` fixture Signed-off-by: Pedro Algarvio --- tests/pytests/unit/states/test_grains.py | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/tests/pytests/unit/states/test_grains.py b/tests/pytests/unit/states/test_grains.py index 99a76a4357f..eacdacb82f6 100644 --- a/tests/pytests/unit/states/test_grains.py +++ b/tests/pytests/unit/states/test_grains.py @@ -1,8 +1,6 @@ """ unit tests for the grains state """ - - import contextlib import os @@ -14,21 +12,14 @@ import salt.utils.files import salt.utils.stringutils import salt.utils.yaml from tests.support.mock import MagicMock, patch -from tests.support.paths import SALT_CODE_DIR @pytest.fixture -def configure_loader_modules(): - grains_test_dir = "__salt_test_state_grains" - if not os.path.exists(os.path.join(SALT_CODE_DIR, grains_test_dir)): - os.makedirs(os.path.join(SALT_CODE_DIR, grains_test_dir)) +def configure_loader_modules(minion_opts): + minion_opts["local"] = True + minion_opts["test"] = False loader_globals = { - "__opts__": { - "test": False, - "conf_file": os.path.join(SALT_CODE_DIR, grains_test_dir, "minion"), - "cachedir": os.path.join(SALT_CODE_DIR, grains_test_dir), - "local": True, - }, + "__opts__": minion_opts, "__salt__": { "cmd.run_all": MagicMock( return_value={"pid": 5, "retcode": 0, "stderr": "", "stdout": ""} From e8d5f8394ec83ec3c4ceae9edf11c874071b6cbc Mon Sep 17 00:00:00 2001 From: Pedro Algarvio Date: Wed, 13 Dec 2023 05:33:06 +0000 Subject: [PATCH 10/11] No `CamelCase` please. Signed-off-by: Pedro Algarvio --- tests/pytests/unit/states/test_grains.py | 248 +++++++++++------------ 1 file changed, 119 insertions(+), 129 deletions(-) diff --git a/tests/pytests/unit/states/test_grains.py b/tests/pytests/unit/states/test_grains.py index eacdacb82f6..8015eaf9340 100644 --- a/tests/pytests/unit/states/test_grains.py +++ b/tests/pytests/unit/states/test_grains.py @@ -36,28 +36,18 @@ def configure_loader_modules(minion_opts): return {grains: loader_globals, grainsmod: loader_globals} -def assertGrainFileContent(grains_string): - if os.path.isdir(grains.__opts__["conf_file"]): - grains_file = os.path.join(grains.__opts__["conf_file"], "grains") - else: - grains_file = os.path.join( - os.path.dirname(grains.__opts__["conf_file"]), "grains" - ) +def assert_grain_file_content(grains_string): + grains_file = os.path.join(grains.__opts__["conf_dir"], "grains") with salt.utils.files.fopen(grains_file, "r") as grf: grains_data = salt.utils.stringutils.to_unicode(grf.read()) assert grains_string == grains_data @contextlib.contextmanager -def setGrains(grains_data): +def set_grains(grains_data): with patch.dict(grains.__grains__, grains_data): with patch.dict(grainsmod.__grains__, grains_data): - if os.path.isdir(grains.__opts__["conf_file"]): - grains_file = os.path.join(grains.__opts__["conf_file"], "grains") - else: - grains_file = os.path.join( - os.path.dirname(grains.__opts__["conf_file"]), "grains" - ) + grains_file = os.path.join(grains.__opts__["conf_dir"], "grains") with salt.utils.files.fopen(grains_file, "w+") as grf: salt.utils.yaml.safe_dump(grains_data, grf, default_flow_style=False) yield @@ -67,7 +57,7 @@ def setGrains(grains_data): def test_exists_missing(): - with setGrains({"a": "aval"}): + with set_grains({"a": "aval"}): ret = grains.exists(name="foo") assert ret["result"] is False assert ret["comment"] == "Grain does not exist" @@ -75,7 +65,7 @@ def test_exists_missing(): def test_exists_found(): - with setGrains({"a": "aval", "foo": "bar"}): + with set_grains({"a": "aval", "foo": "bar"}): # Grain already set ret = grains.exists(name="foo") assert ret["result"] is True @@ -86,7 +76,7 @@ def test_exists_found(): def test_make_hashable(): - with setGrains({"cmplx_lst_grain": [{"a": "aval"}, {"foo": "bar"}]}): + with set_grains({"cmplx_lst_grain": [{"a": "aval"}, {"foo": "bar"}]}): hashable_list = {"cmplx_lst_grain": [{"a": "aval"}, {"foo": "bar"}]} assert grains.make_hashable(grains.__grains__).issubset( grains.make_hashable(hashable_list) @@ -97,23 +87,23 @@ def test_make_hashable(): def test_present_add(): # Set a non existing grain - with setGrains({"a": "aval"}): + with set_grains({"a": "aval"}): ret = grains.present(name="foo", value="bar") assert ret["result"] is True assert ret["changes"] == {"foo": "bar"} assert grains.__grains__ == {"a": "aval", "foo": "bar"} - assertGrainFileContent("a: aval\nfoo: bar\n") + assert_grain_file_content("a: aval\nfoo: bar\n") # Set a non existing nested grain - with setGrains({"a": "aval"}): + with set_grains({"a": "aval"}): ret = grains.present(name="foo:is:nested", value="bar") assert ret["result"] is True assert ret["changes"] == {"foo": {"is": {"nested": "bar"}}} assert grains.__grains__ == {"a": "aval", "foo": {"is": {"nested": "bar"}}} - assertGrainFileContent("a: aval\nfoo:\n is:\n nested: bar\n") + assert_grain_file_content("a: aval\nfoo:\n is:\n nested: bar\n") # Set a non existing nested dict grain - with setGrains({"a": "aval"}): + with set_grains({"a": "aval"}): ret = grains.present(name="foo:is:nested", value={"bar": "is a dict"}) assert ret["result"] is True assert ret["changes"] == {"foo": {"is": {"nested": {"bar": "is a dict"}}}} @@ -121,24 +111,24 @@ def test_present_add(): "a": "aval", "foo": {"is": {"nested": {"bar": "is a dict"}}}, } - assertGrainFileContent( + assert_grain_file_content( "a: aval\nfoo:\n is:\n nested:\n bar: is a dict\n" ) def test_present_add_key_to_existing(): - with setGrains({"a": "aval", "foo": {"k1": "v1"}}): + with set_grains({"a": "aval", "foo": {"k1": "v1"}}): # Fails setting a grain to a dict ret = grains.present(name="foo:k2", value="v2") assert ret["result"] is True assert ret["comment"] == "Set grain foo:k2 to v2" assert ret["changes"] == {"foo": {"k2": "v2", "k1": "v1"}} assert grains.__grains__ == {"a": "aval", "foo": {"k1": "v1", "k2": "v2"}} - assertGrainFileContent("a: aval\nfoo:\n k1: v1\n k2: v2\n") + assert_grain_file_content("a: aval\nfoo:\n k1: v1\n k2: v2\n") def test_present_already_set(): - with setGrains({"a": "aval", "foo": "bar"}): + with set_grains({"a": "aval", "foo": "bar"}): # Grain already set ret = grains.present(name="foo", value="bar") assert ret["result"] is True @@ -146,7 +136,7 @@ def test_present_already_set(): assert ret["changes"] == {} assert grains.__grains__ == {"a": "aval", "foo": "bar"} - with setGrains({"a": "aval", "foo": {"is": {"nested": "bar"}}}): + with set_grains({"a": "aval", "foo": {"is": {"nested": "bar"}}}): # Nested grain already set ret = grains.present(name="foo:is:nested", value="bar") assert ret["result"] is True @@ -154,7 +144,7 @@ def test_present_already_set(): assert ret["changes"] == {} assert grains.__grains__ == {"a": "aval", "foo": {"is": {"nested": "bar"}}} - with setGrains({"a": "aval", "foo": {"is": {"nested": "bar"}}}): + with set_grains({"a": "aval", "foo": {"is": {"nested": "bar"}}}): # Nested dict grain already set ret = grains.present(name="foo:is", value={"nested": "bar"}) assert ret["result"] is True @@ -164,41 +154,41 @@ def test_present_already_set(): def test_present_overwrite(): - with setGrains({"a": "aval", "foo": "bar"}): + with set_grains({"a": "aval", "foo": "bar"}): # Overwrite an existing grain ret = grains.present(name="foo", value="newbar") assert ret["result"] is True assert ret["changes"] == {"foo": "newbar"} assert grains.__grains__ == {"a": "aval", "foo": "newbar"} - assertGrainFileContent("a: aval\nfoo: newbar\n") + assert_grain_file_content("a: aval\nfoo: newbar\n") - with setGrains({"a": "aval", "foo": "bar"}): + with set_grains({"a": "aval", "foo": "bar"}): # Clear a grain (set to None) ret = grains.present(name="foo", value=None) assert ret["result"] is True assert ret["changes"] == {"foo": None} assert grains.__grains__ == {"a": "aval", "foo": None} - assertGrainFileContent("a: aval\nfoo: null\n") + assert_grain_file_content("a: aval\nfoo: null\n") - with setGrains({"a": "aval", "foo": {"is": {"nested": "bar"}}}): + with set_grains({"a": "aval", "foo": {"is": {"nested": "bar"}}}): # Overwrite an existing nested grain ret = grains.present(name="foo:is:nested", value="newbar") assert ret["result"] is True assert ret["changes"] == {"foo": {"is": {"nested": "newbar"}}} assert grains.__grains__ == {"a": "aval", "foo": {"is": {"nested": "newbar"}}} - assertGrainFileContent("a: aval\nfoo:\n is:\n nested: newbar\n") + assert_grain_file_content("a: aval\nfoo:\n is:\n nested: newbar\n") - with setGrains({"a": "aval", "foo": {"is": {"nested": "bar"}}}): + with set_grains({"a": "aval", "foo": {"is": {"nested": "bar"}}}): # Clear a nested grain (set to None) ret = grains.present(name="foo:is:nested", value=None) assert ret["result"] is True assert ret["changes"] == {"foo": {"is": {"nested": None}}} assert grains.__grains__ == {"a": "aval", "foo": {"is": {"nested": None}}} - assertGrainFileContent("a: aval\nfoo:\n is:\n nested: null\n") + assert_grain_file_content("a: aval\nfoo:\n is:\n nested: null\n") def test_present_fail_overwrite(): - with setGrains({"a": "aval", "foo": {"is": {"nested": "val"}}}): + with set_grains({"a": "aval", "foo": {"is": {"nested": "val"}}}): # Overwrite an existing grain ret = grains.present(name="foo:is", value="newbar") assert ret["result"] is False @@ -209,7 +199,7 @@ def test_present_fail_overwrite(): ) assert grains.__grains__ == {"a": "aval", "foo": {"is": {"nested": "val"}}} - with setGrains({"a": "aval", "foo": {"is": {"nested": "val"}}}): + with set_grains({"a": "aval", "foo": {"is": {"nested": "val"}}}): # Clear a grain (set to None) ret = grains.present(name="foo:is", value=None) assert ret["result"] is False @@ -222,7 +212,7 @@ def test_present_fail_overwrite(): def test_present_fails_to_set_dict_or_list(): - with setGrains({"a": "aval", "foo": "bar"}): + with set_grains({"a": "aval", "foo": "bar"}): # Fails to overwrite a grain to a list ret = grains.present(name="foo", value=["l1", "l2"]) assert ret["result"] is False @@ -233,7 +223,7 @@ def test_present_fails_to_set_dict_or_list(): assert ret["changes"] == {} assert grains.__grains__ == {"a": "aval", "foo": "bar"} - with setGrains({"a": "aval", "foo": "bar"}): + with set_grains({"a": "aval", "foo": "bar"}): # Fails setting a grain to a dict ret = grains.present(name="foo", value={"k1": "v1"}) assert ret["result"] is False @@ -244,7 +234,7 @@ def test_present_fails_to_set_dict_or_list(): assert ret["changes"] == {} assert grains.__grains__ == {"a": "aval", "foo": "bar"} - with setGrains({"a": "aval", "foo": {"is": {"nested": "bar"}}}): + with set_grains({"a": "aval", "foo": {"is": {"nested": "bar"}}}): # Fails to overwrite a nested grain to a list ret = grains.present(name="foo,is,nested", value=["l1", "l2"], delimiter=",") assert ret["result"] is False @@ -255,7 +245,7 @@ def test_present_fails_to_set_dict_or_list(): ) assert grains.__grains__ == {"a": "aval", "foo": {"is": {"nested": "bar"}}} - with setGrains({"a": "aval", "foo": {"is": {"nested": "bar"}}}): + with set_grains({"a": "aval", "foo": {"is": {"nested": "bar"}}}): # Fails setting a nested grain to a dict ret = grains.present(name="foo:is:nested", value={"k1": "v1"}) assert ret["result"] is False @@ -268,7 +258,7 @@ def test_present_fails_to_set_dict_or_list(): def test_present_fail_merge_dict(): - with setGrains({"a": "aval", "foo": {"k1": "v1"}}): + with set_grains({"a": "aval", "foo": {"k1": "v1"}}): # Fails setting a grain to a dict ret = grains.present(name="foo", value={"k2": "v2"}) assert ret["result"] is False @@ -277,29 +267,29 @@ def test_present_fail_merge_dict(): == "The key 'foo' exists but is a dict or a list. Use 'force=True' to overwrite." ) assert grains.__grains__ == {"a": "aval", "foo": {"k1": "v1"}} - assertGrainFileContent("a: aval\nfoo:\n k1: v1\n") + assert_grain_file_content("a: aval\nfoo:\n k1: v1\n") def test_present_force_to_set_dict_or_list(): - with setGrains({"a": "aval", "foo": "bar"}): + with set_grains({"a": "aval", "foo": "bar"}): # Force to overwrite a grain to a list ret = grains.present(name="foo", value=["l1", "l2"], force=True) assert ret["result"] is True assert ret["comment"] == "Set grain foo to ['l1', 'l2']" assert ret["changes"] == {"foo": ["l1", "l2"]} assert grains.__grains__ == {"a": "aval", "foo": ["l1", "l2"]} - assertGrainFileContent("a: aval\nfoo:\n- l1\n- l2\n") + assert_grain_file_content("a: aval\nfoo:\n- l1\n- l2\n") - with setGrains({"a": "aval", "foo": "bar"}): + with set_grains({"a": "aval", "foo": "bar"}): # Force setting a grain to a dict ret = grains.present(name="foo", value={"k1": "v1"}, force=True) assert ret["result"] is True assert ret["comment"] == "Set grain foo to {'k1': 'v1'}" assert ret["changes"] == {"foo": {"k1": "v1"}} assert grains.__grains__ == {"a": "aval", "foo": {"k1": "v1"}} - assertGrainFileContent("a: aval\nfoo:\n k1: v1\n") + assert_grain_file_content("a: aval\nfoo:\n k1: v1\n") - with setGrains({"a": "aval", "foo": {"is": {"nested": "bar"}}}): + with set_grains({"a": "aval", "foo": {"is": {"nested": "bar"}}}): # Force to overwrite a nested grain to a list ret = grains.present( name="foo,is,nested", value=["l1", "l2"], delimiter=",", force=True @@ -311,11 +301,11 @@ def test_present_force_to_set_dict_or_list(): "a": "aval", "foo": {"is": {"nested": ["l1", "l2"]}}, } - assertGrainFileContent( + assert_grain_file_content( "a: aval\nfoo:\n is:\n nested:\n - l1\n - l2\n" ) - with setGrains({"a": "aval", "foo": {"is": {"nested": "bar"}, "and": "other"}}): + with set_grains({"a": "aval", "foo": {"is": {"nested": "bar"}, "and": "other"}}): # Force setting a nested grain to a dict ret = grains.present(name="foo:is:nested", value={"k1": "v1"}, force=True) assert ret["result"] is True @@ -327,13 +317,13 @@ def test_present_force_to_set_dict_or_list(): "a": "aval", "foo": {"is": {"nested": {"k1": "v1"}}, "and": "other"}, } - assertGrainFileContent( + assert_grain_file_content( "a: aval\nfoo:\n and: other\n is:\n nested:\n k1: v1\n" ) def test_present_fails_to_convert_value_to_key(): - with setGrains({"a": "aval", "foo": "bar"}): + with set_grains({"a": "aval", "foo": "bar"}): # Fails converting a value to a nested grain key ret = grains.present(name="foo:is:nested", value={"k1": "v1"}) assert ret["result"] is False @@ -346,17 +336,17 @@ def test_present_fails_to_convert_value_to_key(): def test_present_overwrite_test(): with patch.dict(grains.__opts__, {"test": True}): - with setGrains({"a": "aval", "foo": "bar"}): + with set_grains({"a": "aval", "foo": "bar"}): # Overwrite an existing grain ret = grains.present(name="foo", value="newbar") assert ret["result"] is None assert ret["changes"] == {"changed": {"foo": "newbar"}} assert grains.__grains__ == {"a": "aval", "foo": "bar"} - assertGrainFileContent("a: aval\nfoo: bar\n") + assert_grain_file_content("a: aval\nfoo: bar\n") def test_present_convert_value_to_key(): - with setGrains({"a": "aval", "foo": "is"}): + with set_grains({"a": "aval", "foo": "is"}): # Converts a value to a nested grain key ret = grains.present(name="foo:is:nested", value={"k1": "v1"}) assert ret["result"] is True @@ -366,9 +356,9 @@ def test_present_convert_value_to_key(): "a": "aval", "foo": {"is": {"nested": {"k1": "v1"}}}, } - assertGrainFileContent("a: aval\nfoo:\n is:\n nested:\n k1: v1\n") + assert_grain_file_content("a: aval\nfoo:\n is:\n nested:\n k1: v1\n") - with setGrains({"a": "aval", "foo": ["one", "is", "correct"]}): + with set_grains({"a": "aval", "foo": ["one", "is", "correct"]}): # Converts a list element to a nested grain key ret = grains.present(name="foo:is:nested", value={"k1": "v1"}) assert ret["result"] is True @@ -380,7 +370,7 @@ def test_present_convert_value_to_key(): "a": "aval", "foo": ["one", {"is": {"nested": {"k1": "v1"}}}, "correct"], } - assertGrainFileContent( + assert_grain_file_content( "a: aval\nfoo:\n- one\n- is:\n nested:\n k1: v1\n- correct\n" ) @@ -388,14 +378,14 @@ def test_present_convert_value_to_key(): def test_present_unknown_failure(): with patch("salt.modules.grains.setval") as mocked_setval: mocked_setval.return_value = "Failed to set grain foo" - with setGrains({"a": "aval", "foo": "bar"}): + with set_grains({"a": "aval", "foo": "bar"}): # Unknown reason failure ret = grains.present(name="foo", value="baz") assert ret["result"] is False assert ret["comment"] == "Failed to set grain foo" assert ret["changes"] == {} assert grains.__grains__ == {"a": "aval", "foo": "bar"} - assertGrainFileContent("a: aval\nfoo: bar\n") + assert_grain_file_content("a: aval\nfoo: bar\n") # 'absent' function tests: 6 @@ -403,45 +393,45 @@ def test_present_unknown_failure(): def test_absent_already(): # Unset a non existent grain - with setGrains({"a": "aval"}): + with set_grains({"a": "aval"}): ret = grains.absent(name="foo") assert ret["result"] is True assert ret["comment"] == "Grain foo does not exist" assert ret["changes"] == {} assert grains.__grains__ == {"a": "aval"} - assertGrainFileContent("a: aval\n") + assert_grain_file_content("a: aval\n") # Unset a non existent nested grain - with setGrains({"a": "aval"}): + with set_grains({"a": "aval"}): ret = grains.absent(name="foo:is:nested") assert ret["result"] is True assert ret["comment"] == "Grain foo:is:nested does not exist" assert ret["changes"] == {} assert grains.__grains__ == {"a": "aval"} - assertGrainFileContent("a: aval\n") + assert_grain_file_content("a: aval\n") def test_absent_unset(): # Unset a grain - with setGrains({"a": "aval", "foo": "bar"}): + with set_grains({"a": "aval", "foo": "bar"}): ret = grains.absent(name="foo") assert ret["result"] is True assert ret["comment"] == "Value for grain foo was set to None" assert ret["changes"] == {"grain": "foo", "value": None} assert grains.__grains__ == {"a": "aval", "foo": None} - assertGrainFileContent("a: aval\nfoo: null\n") + assert_grain_file_content("a: aval\nfoo: null\n") # Unset grain when its value is False - with setGrains({"a": "aval", "foo": False}): + with set_grains({"a": "aval", "foo": False}): ret = grains.absent(name="foo") assert ret["result"] is True assert ret["comment"] == "Value for grain foo was set to None" assert ret["changes"] == {"grain": "foo", "value": None} assert grains.__grains__ == {"a": "aval", "foo": None} - assertGrainFileContent("a: aval\nfoo: null\n") + assert_grain_file_content("a: aval\nfoo: null\n") # Unset a nested grain - with setGrains( + with set_grains( {"a": "aval", "foo": ["order", {"is": {"nested": "bar"}}, "correct"]} ): ret = grains.absent(name="foo,is,nested", delimiter=",") @@ -452,12 +442,12 @@ def test_absent_unset(): "a": "aval", "foo": ["order", {"is": {"nested": None}}, "correct"], } - assertGrainFileContent( + assert_grain_file_content( "a: aval\nfoo:\n- order\n- is:\n nested: null\n- correct\n" ) # Unset a nested value don't change anything - with setGrains({"a": "aval", "foo": ["order", {"is": "nested"}, "correct"]}): + with set_grains({"a": "aval", "foo": ["order", {"is": "nested"}, "correct"]}): ret = grains.absent(name="foo:is:nested") assert ret["result"] is True assert ret["comment"] == "Grain foo:is:nested does not exist" @@ -466,23 +456,23 @@ def test_absent_unset(): "a": "aval", "foo": ["order", {"is": "nested"}, "correct"], } - assertGrainFileContent("a: aval\nfoo:\n- order\n- is: nested\n- correct\n") + assert_grain_file_content("a: aval\nfoo:\n- order\n- is: nested\n- correct\n") def test_absent_unset_test(): with patch.dict(grains.__opts__, {"test": True}): - with setGrains({"a": "aval", "foo": "bar"}): + with set_grains({"a": "aval", "foo": "bar"}): # Overwrite an existing grain ret = grains.absent(name="foo") assert ret["result"] is None assert ret["changes"] == {"grain": "foo", "value": None} assert grains.__grains__ == {"a": "aval", "foo": "bar"} - assertGrainFileContent("a: aval\nfoo: bar\n") + assert_grain_file_content("a: aval\nfoo: bar\n") def test_absent_fails_nested_complex_grain(): # Unset a nested complex grain - with setGrains( + with set_grains( {"a": "aval", "foo": ["order", {"is": {"nested": "bar"}}, "correct"]} ): ret = grains.absent(name="foo:is") @@ -496,14 +486,14 @@ def test_absent_fails_nested_complex_grain(): "a": "aval", "foo": ["order", {"is": {"nested": "bar"}}, "correct"], } - assertGrainFileContent( + assert_grain_file_content( "a: aval\nfoo:\n- order\n- is:\n nested: bar\n- correct\n" ) def test_absent_force_nested_complex_grain(): # Unset a nested complex grain - with setGrains( + with set_grains( {"a": "aval", "foo": ["order", {"is": {"nested": "bar"}}, "correct"]} ): ret = grains.absent(name="foo:is", force=True) @@ -514,30 +504,30 @@ def test_absent_force_nested_complex_grain(): "a": "aval", "foo": ["order", {"is": None}, "correct"], } - assertGrainFileContent("a: aval\nfoo:\n- order\n- is: null\n- correct\n") + assert_grain_file_content("a: aval\nfoo:\n- order\n- is: null\n- correct\n") def test_absent_delete(): # Delete a grain - with setGrains({"a": "aval", "foo": "bar"}): + with set_grains({"a": "aval", "foo": "bar"}): ret = grains.absent(name="foo", destructive=True) assert ret["result"] is True assert ret["comment"] == "Grain foo was deleted" assert ret["changes"] == {"deleted": "foo"} assert grains.__grains__ == {"a": "aval"} - assertGrainFileContent("a: aval\n") + assert_grain_file_content("a: aval\n") # Delete a previously unset grain - with setGrains({"a": "aval", "foo": None}): + with set_grains({"a": "aval", "foo": None}): ret = grains.absent(name="foo", destructive=True) assert ret["result"] is True assert ret["comment"] == "Grain foo was deleted" assert ret["changes"] == {"deleted": "foo"} assert grains.__grains__ == {"a": "aval"} - assertGrainFileContent("a: aval\n") + assert_grain_file_content("a: aval\n") # Delete a nested grain - with setGrains( + with set_grains( { "a": "aval", "foo": [ @@ -555,7 +545,7 @@ def test_absent_delete(): "a": "aval", "foo": ["order", {"is": {"other": "value"}}, "correct"], } - assertGrainFileContent( + assert_grain_file_content( "a: aval\nfoo:\n- order\n- is:\n other: value\n- correct\n" ) @@ -565,40 +555,40 @@ def test_absent_delete(): def test_append(): # Append to an existing list - with setGrains({"a": "aval", "foo": ["bar"]}): + with set_grains({"a": "aval", "foo": ["bar"]}): ret = grains.append(name="foo", value="baz") assert ret["result"] is True assert ret["comment"] == "Value baz was added to grain foo" assert ret["changes"] == {"added": "baz"} assert grains.__grains__ == {"a": "aval", "foo": ["bar", "baz"]} - assertGrainFileContent("a: aval\nfoo:\n- bar\n- baz\n") + assert_grain_file_content("a: aval\nfoo:\n- bar\n- baz\n") def test_append_nested(): # Append to an existing nested list - with setGrains({"a": "aval", "foo": {"list": ["bar"]}}): + with set_grains({"a": "aval", "foo": {"list": ["bar"]}}): ret = grains.append(name="foo,list", value="baz", delimiter=",") assert ret["result"] is True assert ret["comment"] == "Value baz was added to grain foo:list" assert ret["changes"] == {"added": "baz"} assert grains.__grains__ == {"a": "aval", "foo": {"list": ["bar", "baz"]}} - assertGrainFileContent("a: aval\nfoo:\n list:\n - bar\n - baz\n") + assert_grain_file_content("a: aval\nfoo:\n list:\n - bar\n - baz\n") def test_append_already(): # Append to an existing list - with setGrains({"a": "aval", "foo": ["bar"]}): + with set_grains({"a": "aval", "foo": ["bar"]}): ret = grains.append(name="foo", value="bar") assert ret["result"] is True assert ret["comment"] == "Value bar is already in the list " + "for grain foo" assert ret["changes"] == {} assert grains.__grains__ == {"a": "aval", "foo": ["bar"]} - assertGrainFileContent("a: aval\nfoo:\n- bar\n") + assert_grain_file_content("a: aval\nfoo:\n- bar\n") def test_append_fails_not_a_list(): # Fail to append to an existing grain, not a list - with setGrains({"a": "aval", "foo": {"bar": "val"}}): + with set_grains({"a": "aval", "foo": {"bar": "val"}}): ret = grains.append(name="foo", value="baz") assert ret["result"] is False assert ret["comment"] == "Grain foo is not a valid list" @@ -608,18 +598,18 @@ def test_append_fails_not_a_list(): def test_append_convert_to_list(): # Append to an existing grain, converting to a list - with setGrains({"a": "aval", "foo": {"bar": "val"}}): - assertGrainFileContent("a: aval\nfoo:\n bar: val\n") + with set_grains({"a": "aval", "foo": {"bar": "val"}}): + assert_grain_file_content("a: aval\nfoo:\n bar: val\n") ret = grains.append(name="foo", value="baz", convert=True) assert ret["result"] is True assert ret["comment"] == "Value baz was added to grain foo" assert ret["changes"] == {"added": "baz"} assert grains.__grains__ == {"a": "aval", "foo": [{"bar": "val"}, "baz"]} - assertGrainFileContent("a: aval\nfoo:\n- bar: val\n- baz\n") + assert_grain_file_content("a: aval\nfoo:\n- bar: val\n- baz\n") # Append to an existing grain, converting to a list a multi-value dict - with setGrains({"a": "aval", "foo": {"bar": "val", "other": "value"}}): - assertGrainFileContent("a: aval\nfoo:\n bar: val\n other: value\n") + with set_grains({"a": "aval", "foo": {"bar": "val", "other": "value"}}): + assert_grain_file_content("a: aval\nfoo:\n bar: val\n other: value\n") ret = grains.append(name="foo", value="baz", convert=True) assert ret["result"] is True assert ret["comment"] == "Value baz was added to grain foo" @@ -628,12 +618,12 @@ def test_append_convert_to_list(): "a": "aval", "foo": [{"bar": "val", "other": "value"}, "baz"], } - assertGrainFileContent("a: aval\nfoo:\n- bar: val\n other: value\n- baz\n") + assert_grain_file_content("a: aval\nfoo:\n- bar: val\n other: value\n- baz\n") def test_append_fails_inexistent(): # Append to a non existing grain - with setGrains({"a": "aval"}): + with set_grains({"a": "aval"}): ret = grains.append(name="foo", value="bar") assert ret["result"] is False assert ret["comment"] == "Grain foo does not exist" @@ -643,30 +633,30 @@ def test_append_fails_inexistent(): def test_append_convert_to_list_empty(): # Append to an existing list - with setGrains({"foo": None}): + with set_grains({"foo": None}): ret = grains.append(name="foo", value="baz", convert=True) assert ret["result"] is True assert ret["comment"] == "Value baz was added to grain foo" assert ret["changes"] == {"added": "baz"} assert grains.__grains__ == {"foo": ["baz"]} - assertGrainFileContent("foo:\n- baz\n") + assert_grain_file_content("foo:\n- baz\n") # 'list_present' function tests: 7 def test_list_present(): - with setGrains({"a": "aval", "foo": ["bar"]}): + with set_grains({"a": "aval", "foo": ["bar"]}): ret = grains.list_present(name="foo", value="baz") assert ret["result"] is True assert ret["comment"] == "Append value baz to grain foo" assert ret["changes"] == {"new": {"foo": ["bar", "baz"]}} assert grains.__grains__ == {"a": "aval", "foo": ["bar", "baz"]} - assertGrainFileContent("a: aval\nfoo:\n- bar\n- baz\n") + assert_grain_file_content("a: aval\nfoo:\n- bar\n- baz\n") def test_list_present_nested(): - with setGrains({"a": "aval", "foo": {"is": {"nested": ["bar"]}}}): + with set_grains({"a": "aval", "foo": {"is": {"nested": ["bar"]}}}): ret = grains.list_present(name="foo,is,nested", value="baz", delimiter=",") assert ret["result"] is True assert ret["comment"] == "Append value baz to grain foo:is:nested" @@ -675,63 +665,63 @@ def test_list_present_nested(): "a": "aval", "foo": {"is": {"nested": ["bar", "baz"]}}, } - assertGrainFileContent( + assert_grain_file_content( "a: aval\nfoo:\n is:\n nested:\n - bar\n - baz\n" ) def test_list_present_inexistent(): - with setGrains({"a": "aval"}): + with set_grains({"a": "aval"}): ret = grains.list_present(name="foo", value="baz") assert ret["result"] is True assert ret["comment"] == "Append value baz to grain foo" assert ret["changes"] == {"new": {"foo": ["baz"]}} assert grains.__grains__ == {"a": "aval", "foo": ["baz"]} - assertGrainFileContent("a: aval\nfoo:\n- baz\n") + assert_grain_file_content("a: aval\nfoo:\n- baz\n") def test_list_present_inexistent_nested(): - with setGrains({"a": "aval"}): + with set_grains({"a": "aval"}): ret = grains.list_present(name="foo:is:nested", value="baz") assert ret["result"] is True assert ret["comment"] == "Append value baz to grain foo:is:nested" assert ret["changes"] == {"new": {"foo": {"is": {"nested": ["baz"]}}}} assert grains.__grains__ == {"a": "aval", "foo": {"is": {"nested": ["baz"]}}} - assertGrainFileContent("a: aval\nfoo:\n is:\n nested:\n - baz\n") + assert_grain_file_content("a: aval\nfoo:\n is:\n nested:\n - baz\n") def test_list_present_not_a_list(): - with setGrains({"a": "aval", "foo": "bar"}): + with set_grains({"a": "aval", "foo": "bar"}): ret = grains.list_present(name="foo", value="baz") assert ret["result"] is False assert ret["comment"] == "Grain foo is not a valid list" assert ret["changes"] == {} assert grains.__grains__ == {"a": "aval", "foo": "bar"} - assertGrainFileContent("a: aval\nfoo: bar\n") + assert_grain_file_content("a: aval\nfoo: bar\n") def test_list_present_nested_already(): - with setGrains({"a": "aval", "b": {"foo": ["bar"]}}): + with set_grains({"a": "aval", "b": {"foo": ["bar"]}}): ret = grains.list_present(name="b:foo", value="bar") assert ret["result"] is True assert ret["comment"] == "Value bar is already in grain b:foo" assert ret["changes"] == {} assert grains.__grains__ == {"a": "aval", "b": {"foo": ["bar"]}} - assertGrainFileContent("a: aval\nb:\n foo:\n - bar\n") + assert_grain_file_content("a: aval\nb:\n foo:\n - bar\n") def test_list_present_already(): - with setGrains({"a": "aval", "foo": ["bar"]}): + with set_grains({"a": "aval", "foo": ["bar"]}): ret = grains.list_present(name="foo", value="bar") assert ret["result"] is True assert ret["comment"] == "Value bar is already in grain foo" assert ret["changes"] == {} assert grains.__grains__ == {"a": "aval", "foo": ["bar"]} - assertGrainFileContent("a: aval\nfoo:\n- bar\n") + assert_grain_file_content("a: aval\nfoo:\n- bar\n") def test_list_present_unknown_failure(): - with setGrains({"a": "aval", "foo": ["bar"]}): + with set_grains({"a": "aval", "foo": ["bar"]}): # Unknown reason failure with patch.dict(grainsmod.__salt__, {"grains.append": MagicMock()}): @@ -740,67 +730,67 @@ def test_list_present_unknown_failure(): assert ret["comment"] == "Failed append value baz to grain foo" assert ret["changes"] == {} assert grains.__grains__ == {"a": "aval", "foo": ["bar"]} - assertGrainFileContent("a: aval\nfoo:\n- bar\n") + assert_grain_file_content("a: aval\nfoo:\n- bar\n") # 'list_absent' function tests: 6 def test_list_absent(): - with setGrains({"a": "aval", "foo": ["bar"]}): + with set_grains({"a": "aval", "foo": ["bar"]}): ret = grains.list_absent(name="foo", value="bar") assert ret["result"] is True assert ret["comment"] == "Value bar was deleted from grain foo" assert ret["changes"] == {"deleted": ["bar"]} assert grains.__grains__ == {"a": "aval", "foo": []} - assertGrainFileContent("a: aval\nfoo: []\n") + assert_grain_file_content("a: aval\nfoo: []\n") def test_list_absent_nested(): - with setGrains({"a": "aval", "foo": {"list": ["bar"]}}): + with set_grains({"a": "aval", "foo": {"list": ["bar"]}}): ret = grains.list_absent(name="foo:list", value="bar") assert ret["result"] is True assert ret["comment"] == "Value bar was deleted from grain foo:list" assert ret["changes"] == {"deleted": ["bar"]} assert grains.__grains__ == {"a": "aval", "foo": {"list": []}} - assertGrainFileContent("a: aval\nfoo:\n list: []\n") + assert_grain_file_content("a: aval\nfoo:\n list: []\n") def test_list_absent_inexistent(): - with setGrains({"a": "aval"}): + with set_grains({"a": "aval"}): ret = grains.list_absent(name="foo", value="baz") assert ret["result"] is True assert ret["comment"] == "Grain foo does not exist" assert ret["changes"] == {} assert grains.__grains__ == {"a": "aval"} - assertGrainFileContent("a: aval\n") + assert_grain_file_content("a: aval\n") def test_list_absent_inexistent_nested(): - with setGrains({"a": "aval"}): + with set_grains({"a": "aval"}): ret = grains.list_absent(name="foo:list", value="baz") assert ret["result"] is True assert ret["comment"] == "Grain foo:list does not exist" assert ret["changes"] == {} assert grains.__grains__ == {"a": "aval"} - assertGrainFileContent("a: aval\n") + assert_grain_file_content("a: aval\n") def test_list_absent_not_a_list(): - with setGrains({"a": "aval", "foo": "bar"}): + with set_grains({"a": "aval", "foo": "bar"}): ret = grains.list_absent(name="foo", value="bar") assert ret["result"] is False assert ret["comment"] == "Grain foo is not a valid list" assert ret["changes"] == {} assert grains.__grains__ == {"a": "aval", "foo": "bar"} - assertGrainFileContent("a: aval\nfoo: bar\n") + assert_grain_file_content("a: aval\nfoo: bar\n") def test_list_absent_already(): - with setGrains({"a": "aval", "foo": ["bar"]}): + with set_grains({"a": "aval", "foo": ["bar"]}): ret = grains.list_absent(name="foo", value="baz") assert ret["result"] is True assert ret["comment"] == "Value baz is absent from grain foo" assert ret["changes"] == {} assert grains.__grains__ == {"a": "aval", "foo": ["bar"]} - assertGrainFileContent("a: aval\nfoo:\n- bar\n") + assert_grain_file_content("a: aval\nfoo:\n- bar\n") From 4522bb2aba38254c73001b4c0e7a6bb166da53c1 Mon Sep 17 00:00:00 2001 From: Frode Gundersen Date: Fri, 13 Jan 2023 20:24:51 +0000 Subject: [PATCH 11/11] migrate test_tomcat to pytest --- tests/pytests/unit/modules/test_tomcat.py | 58 +++++++++++++++++++++++ tests/unit/modules/test_tomcat.py | 58 ----------------------- 2 files changed, 58 insertions(+), 58 deletions(-) create mode 100644 tests/pytests/unit/modules/test_tomcat.py delete mode 100644 tests/unit/modules/test_tomcat.py diff --git a/tests/pytests/unit/modules/test_tomcat.py b/tests/pytests/unit/modules/test_tomcat.py new file mode 100644 index 00000000000..869c3f96c85 --- /dev/null +++ b/tests/pytests/unit/modules/test_tomcat.py @@ -0,0 +1,58 @@ +""" + Tests cases for salt.modules.tomcat +""" + + +import io +import urllib.request + +import pytest + +import salt.modules.tomcat as tomcat +from tests.support.mock import MagicMock, patch + + +@pytest.fixture +def configure_loader_modules(): + return {tomcat: {}} + + +def test_tomcat_wget_no_bytestring(): + responses = { + "string": io.StringIO("Best response ever\r\nAnd you know it!"), + "bytes": io.BytesIO(b"Best response ever\r\nAnd you know it!"), + } + + string_mock = MagicMock(return_value=responses["string"]) + bytes_mock = MagicMock(return_value=responses["bytes"]) + with patch( + "salt.modules.tomcat._auth", + MagicMock( + return_value=urllib.request.build_opener( + urllib.request.HTTPBasicAuthHandler(), + urllib.request.HTTPDigestAuthHandler(), + ) + ), + ): + with patch("urllib.request.urlopen", string_mock): + response = tomcat._wget("tomcat.wait", url="http://localhost:8080/nofail") + for line in response["msg"]: + assert isinstance(line, str) + + with patch("urllib.request.urlopen", bytes_mock): + try: + response = tomcat._wget( + "tomcat.wait", url="http://localhost:8080/nofail" + ) + except TypeError as type_error: + if ( + type_error.args[0] + == "startswith first arg must be bytes or a tuple of bytes," + " not str" + ): + print("Got back a byte string, should've been a string") + else: + raise type_error + + for line in response["msg"]: + assert isinstance(line, str) diff --git a/tests/unit/modules/test_tomcat.py b/tests/unit/modules/test_tomcat.py deleted file mode 100644 index 4de0500b29f..00000000000 --- a/tests/unit/modules/test_tomcat.py +++ /dev/null @@ -1,58 +0,0 @@ -import io -import urllib.request - -import salt.modules.tomcat as tomcat -from tests.support.mixins import LoaderModuleMockMixin -from tests.support.mock import MagicMock, patch -from tests.support.unit import TestCase - - -class TomcatTestCasse(TestCase, LoaderModuleMockMixin): - """ - Tests cases for salt.modules.tomcat - """ - - def setup_loader_modules(self): - return {tomcat: {}} - - def test_tomcat_wget_no_bytestring(self): - responses = { - "string": io.StringIO("Best response ever\r\nAnd you know it!"), - "bytes": io.BytesIO(b"Best response ever\r\nAnd you know it!"), - } - - string_mock = MagicMock(return_value=responses["string"]) - bytes_mock = MagicMock(return_value=responses["bytes"]) - with patch( - "salt.modules.tomcat._auth", - MagicMock( - return_value=urllib.request.build_opener( - urllib.request.HTTPBasicAuthHandler(), - urllib.request.HTTPDigestAuthHandler(), - ) - ), - ): - with patch("urllib.request.urlopen", string_mock): - response = tomcat._wget( - "tomcat.wait", url="http://localhost:8080/nofail" - ) - for line in response["msg"]: - self.assertIsInstance(line, str) - - with patch("urllib.request.urlopen", bytes_mock): - try: - response = tomcat._wget( - "tomcat.wait", url="http://localhost:8080/nofail" - ) - except TypeError as type_error: - if ( - type_error.args[0] - == "startswith first arg must be bytes or a tuple of bytes," - " not str" - ): - self.fail("Got back a byte string, should've been a string") - else: - raise type_error - - for line in response["msg"]: - self.assertIsInstance(line, str)