text: """
  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\n" "foo:\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")
  