"Fossies" - the Fresh Open Source Software Archive

Member "salt-3002.2/tests/unit/states/test_module.py" (18 Nov 2020, 16706 Bytes) of package /linux/misc/salt-3002.2.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Python source code syntax highlighting (style: standard) with prefixed line numbers. Alternatively you can here view or download the uninterpreted source code file. See also the latest Fossies "Diffs" side-by-side code changes report for "test_module.py": 3002.1_vs_3002.2.

    1 """
    2     :codeauthor: Nicole Thomas (nicole@saltstack.com)
    3 """
    4 
    5 
    6 import logging
    7 from inspect import ArgSpec
    8 
    9 import salt.states.module as module
   10 from tests.support.mixins import LoaderModuleMockMixin
   11 from tests.support.mock import MagicMock, patch
   12 from tests.support.unit import TestCase
   13 
   14 log = logging.getLogger(__name__)
   15 
   16 CMD = "foo.bar"
   17 
   18 STATE_APPLY_RET = {
   19     "module_|-test2_|-state.apply_|-run": {
   20         "comment": "Module function state.apply executed",
   21         "name": "state.apply",
   22         "start_time": "16:11:48.818932",
   23         "result": False,
   24         "duration": 179.439,
   25         "__run_num__": 0,
   26         "changes": {
   27             "ret": {
   28                 "module_|-test3_|-state.apply_|-run": {
   29                     "comment": "Module function state.apply executed",
   30                     "name": "state.apply",
   31                     "start_time": "16:11:48.904796",
   32                     "result": True,
   33                     "duration": 89.522,
   34                     "__run_num__": 0,
   35                     "changes": {
   36                         "ret": {
   37                             "module_|-test4_|-cmd.run_|-run": {
   38                                 "comment": "Module function cmd.run executed",
   39                                 "name": "cmd.run",
   40                                 "start_time": "16:11:48.988574",
   41                                 "result": True,
   42                                 "duration": 4.543,
   43                                 "__run_num__": 0,
   44                                 "changes": {"ret": "Wed Mar  7 16:11:48 CET 2018"},
   45                                 "__id__": "test4",
   46                             }
   47                         }
   48                     },
   49                     "__id__": "test3",
   50                 },
   51                 "module_|-test3_fail_|-test3_fail_|-run": {
   52                     "comment": "Module function test3_fail is not available",
   53                     "name": "test3_fail",
   54                     "start_time": "16:11:48.994607",
   55                     "result": False,
   56                     "duration": 0.466,
   57                     "__run_num__": 1,
   58                     "changes": {},
   59                     "__id__": "test3_fail",
   60                 },
   61             }
   62         },
   63         "__id__": "test2",
   64     }
   65 }
   66 
   67 
   68 def _mocked_func_named(name, names=("Fred", "Swen",)):
   69     """
   70     Mocked function with named defaults.
   71 
   72     :param name:
   73     :param names:
   74     :return:
   75     """
   76     return {"name": name, "names": names}
   77 
   78 
   79 def _mocked_func_args(*args):
   80     """
   81     Mocked function with args.
   82 
   83     :param args:
   84     :return:
   85     """
   86     assert args == ("foo", "bar")
   87     return {"args": args}
   88 
   89 
   90 def _mocked_none_return(ret=None):
   91     """
   92     Mocked function returns None
   93     :return:
   94     """
   95     return ret
   96 
   97 
   98 class ModuleStateTest(TestCase, LoaderModuleMockMixin):
   99     """
  100     Tests module state (salt/states/module.py)
  101     """
  102 
  103     def setup_loader_modules(self):
  104         return {module: {"__opts__": {"test": False}, "__salt__": {CMD: MagicMock()}}}
  105 
  106     @classmethod
  107     def setUpClass(cls):
  108         cls.aspec = ArgSpec(
  109             args=["hello", "world"], varargs=None, keywords=None, defaults=False
  110         )
  111 
  112         cls.bspec = ArgSpec(args=[], varargs="names", keywords="kwargs", defaults=None)
  113 
  114     @classmethod
  115     def tearDownClass(cls):
  116         del cls.aspec
  117         del cls.bspec
  118 
  119     def test_run_module_not_available(self):
  120         """
  121         Tests the return of module.run state when the module function is not available.
  122         :return:
  123         """
  124         with patch.dict(module.__salt__, {}, clear=True), patch.dict(
  125             module.__opts__, {"use_superseded": ["module.run"]}
  126         ):
  127             ret = module.run(**{CMD: None})
  128         if ret["comment"] != "Unavailable function: {}.".format(CMD) or ret["result"]:
  129             self.fail("module.run did not fail as expected: {}".format(ret))
  130 
  131     def test_module_run_hidden_varargs(self):
  132         """
  133         Tests the return of module.run state when hidden varargs are used with
  134         wrong type.
  135         """
  136         with patch(
  137             "salt.utils.args.get_function_argspec", MagicMock(return_value=self.bspec)
  138         ):
  139             ret = module._run(CMD, m_names="anyname")
  140         self.assertEqual(ret["comment"], "'names' must be a list.")
  141 
  142     def test_run_testmode(self):
  143         """
  144         Tests the return of the module.run state when test=True is passed.
  145         :return:
  146         """
  147         with patch.dict(
  148             module.__opts__, {"test": True, "use_superseded": ["module.run"]}
  149         ):
  150             ret = module.run(**{CMD: None})
  151         if (
  152             ret["comment"] != "Function {} to be executed.".format(CMD)
  153             or not ret["result"]
  154         ):
  155             self.fail("module.run failed: {}".format(ret))
  156 
  157     def test_run_missing_arg(self):
  158         """
  159         Tests the return of module.run state when arguments are missing
  160         :return:
  161         """
  162         with patch.dict(module.__salt__, {CMD: _mocked_func_named}), patch.dict(
  163             module.__opts__, {"use_superseded": ["module.run"]}
  164         ):
  165             ret = module.run(**{CMD: None})
  166         self.assertEqual(
  167             ret["comment"], "'{}' failed: Missing arguments: name".format(CMD)
  168         )
  169 
  170     def test_run_correct_arg(self):
  171         """
  172         Tests the return of module.run state when arguments are correct
  173         :return:
  174         """
  175         with patch.dict(module.__salt__, {CMD: _mocked_func_named}), patch.dict(
  176             module.__opts__, {"use_superseded": ["module.run"]}
  177         ):
  178             ret = module.run(**{CMD: ["Fred"]})
  179         if ret["comment"] != "{}: Success".format(CMD) or not ret["result"]:
  180             self.fail("module.run failed: {}".format(ret))
  181 
  182     def test_run_state_apply_result_false(self):
  183         """
  184         Tests the 'result' of module.run that calls state.apply execution module
  185         :return:
  186         """
  187         with patch.dict(
  188             module.__salt__, {"state.apply": MagicMock(return_value=STATE_APPLY_RET)}
  189         ), patch.dict(module.__opts__, {"use_deprecated": ["module.run"]}):
  190             ret = module.run(**{"name": "state.apply", "mods": "test2"})
  191         self.assertFalse(ret["result"])
  192 
  193     def test_run_service_status_dead(self):
  194         """
  195         Tests the 'result' of module.run that calls service.status when
  196         service is dead or does not exist
  197         """
  198         func = "service.status"
  199         with patch.dict(
  200             module.__salt__, {func: MagicMock(return_value=False)}
  201         ), patch.dict(module.__opts__, {"use_superseded": ["module.run"]}):
  202             ret = module.run(
  203                 **{
  204                     "name": "test_service_state",
  205                     "service.status": {"name": "doesnotexist"},
  206                 }
  207             )
  208             self.assertEqual(
  209                 ret,
  210                 {
  211                     "name": ["service.status"],
  212                     "changes": {},
  213                     "comment": "'service.status': False",
  214                     "result": False,
  215                 },
  216             )
  217 
  218     def test_run_unexpected_keywords(self):
  219         with patch.dict(module.__salt__, {CMD: _mocked_func_args}), patch.dict(
  220             module.__opts__, {"use_superseded": ["module.run"]}
  221         ):
  222             ret = module.run(**{CMD: [{"foo": "bar"}]})
  223             module_function = module.__salt__[CMD].__name__
  224         self.assertEqual(
  225             ret["comment"],
  226             (
  227                 "'{}' failed: {}() got an unexpected keyword argument "
  228                 "'foo'".format(CMD, module_function)
  229             ),
  230         )
  231         self.assertFalse(ret["result"])
  232 
  233     def test_run_args(self):
  234         """
  235         Test unnamed args.
  236         :return:
  237         """
  238         with patch.dict(module.__salt__, {CMD: _mocked_func_args}), patch.dict(
  239             module.__opts__, {"use_superseded": ["module.run"]}
  240         ):
  241             ret = module.run(**{CMD: ["foo", "bar"]})
  242         self.assertTrue(ret["result"])
  243         self.assertEqual(ret["changes"], {CMD: {"args": ("foo", "bar")}})
  244 
  245     def test_run_42270(self):
  246         """
  247         Test example provided in issue 42270
  248         """
  249 
  250         def test_func(arg1, arg2, **kwargs):
  251             return {"args": [arg1, arg2], "kwargs": kwargs or {}}
  252 
  253         with patch.dict(module.__salt__, {CMD: test_func}), patch.dict(
  254             module.__opts__, {"use_superseded": ["module.run"]}
  255         ):
  256             ret = module.run(**{CMD: ["bla", {"example": "bla"}]})
  257         self.assertFalse(ret["result"])
  258         self.assertEqual(
  259             ret["comment"], "'{}' failed: Missing arguments: arg2".format(CMD)
  260         )
  261 
  262     def test_run_42270_kwargs_to_args(self):
  263         """
  264         Test module.run filling in args with kwargs with the same name.
  265         """
  266 
  267         def test_func(arg1, arg2, arg3, *args, **kwargs):
  268             return {"args": [arg1, arg2, arg3] + list(args), "kwargs": kwargs}
  269 
  270         with patch.dict(module.__salt__, {CMD: test_func}), patch.dict(
  271             module.__opts__, {"use_superseded": ["module.run"]}
  272         ):
  273             ret = module.run(**{CMD: ["foo", "bar", {"arg3": "baz"}, {"foo": "bar"}]})
  274         self.assertTrue(ret["result"])
  275         self.assertEqual(
  276             ret["changes"],
  277             {CMD: {"args": ["foo", "bar", "baz"], "kwargs": {"foo": "bar"}}},
  278         )
  279 
  280     def test_run_none_return(self):
  281         """
  282         Test handling of a broken function that returns None.
  283         :return:
  284         """
  285         with patch.dict(module.__salt__, {CMD: _mocked_none_return}), patch.dict(
  286             module.__opts__, {"use_superseded": ["module.run"]}
  287         ):
  288             ret = module.run(**{CMD: None})
  289         self.assertTrue(ret["result"])
  290         self.assertEqual(ret["changes"], {CMD: None})
  291 
  292     def test_run_typed_return(self):
  293         """
  294         Test handling of a broken function that returns any type.
  295         :return:
  296         """
  297         for val in [
  298             1,
  299             0,
  300             "a",
  301             "",
  302             (1, 2,),
  303             (),
  304             [1, 2],
  305             [],
  306             {"a": "b"},
  307             {},
  308             True,
  309             False,
  310         ]:
  311             with patch.dict(module.__salt__, {CMD: _mocked_none_return}), patch.dict(
  312                 module.__opts__, {"use_superseded": ["module.run"]}
  313             ):
  314                 log.debug("test_run_typed_return: trying %s", val)
  315                 ret = module.run(**{CMD: [{"ret": val}]})
  316             if val is False:
  317                 self.assertFalse(ret["result"])
  318                 self.assertEqual(ret["comment"], "'foo.bar': False")
  319             else:
  320                 self.assertTrue(ret["result"])
  321 
  322     def test_run_batch_call(self):
  323         """
  324         Test batch call
  325         :return:
  326         """
  327         with patch.dict(
  328             module.__opts__, {"use_superseded": ["module.run"]}
  329         ), patch.dict(
  330             module.__salt__,
  331             {
  332                 "first": _mocked_none_return,
  333                 "second": _mocked_none_return,
  334                 "third": _mocked_none_return,
  335             },
  336             clear=True,
  337         ):
  338             for f_name in module.__salt__:
  339                 log.debug("test_run_batch_call: trying %s", f_name)
  340                 ret = module.run(**{f_name: None})
  341                 self.assertTrue(ret["result"])
  342 
  343     def test_module_run_module_not_available(self):
  344         """
  345         Tests the return of module.run state when the module function
  346         name isn't available
  347         """
  348         with patch.dict(module.__salt__, {}, clear=True):
  349             ret = module._run(CMD)
  350         self.assertFalse(ret["result"])
  351         self.assertEqual(
  352             ret["comment"], "Module function {} is not available".format(CMD)
  353         )
  354 
  355     def test_module_run_test_true(self):
  356         """
  357         Tests the return of module.run state when test=True is passed in
  358         """
  359         with patch.dict(module.__opts__, {"test": True}):
  360             ret = module._run(CMD)
  361         self.assertEqual(
  362             ret["comment"], "Module function {} is set to execute".format(CMD)
  363         )
  364 
  365     def test_module_run_missing_arg(self):
  366         """
  367         Tests the return of module.run state when arguments are missing
  368         """
  369         with patch(
  370             "salt.utils.args.get_function_argspec", MagicMock(return_value=self.aspec)
  371         ):
  372             ret = module._run(CMD)
  373         self.assertIn("The following arguments are missing:", ret["comment"])
  374         self.assertIn("world", ret["comment"])
  375         self.assertIn("hello", ret["comment"])
  376 
  377     def test_call_function_named_args(self):
  378         """
  379         Test _call_function routine when params are named. Their position ordering should not matter.
  380 
  381         :return:
  382         """
  383         with patch.dict(
  384             module.__salt__,
  385             {"testfunc": lambda a, b, c, *args, **kwargs: (a, b, c, args, kwargs)},
  386             clear=True,
  387         ):
  388             self.assertEqual(
  389                 module._call_function(
  390                     "testfunc", func_args=[{"a": 1}, {"b": 2}, {"c": 3}]
  391                 ),
  392                 (1, 2, 3, (), {}),
  393             )
  394             self.assertEqual(
  395                 module._call_function(
  396                     "testfunc", func_args=[{"c": 3}, {"a": 1}, {"b": 2}]
  397                 ),
  398                 (1, 2, 3, (), {}),
  399             )
  400 
  401             self.assertEqual(
  402                 module._call_function("testfunc", func_kwargs={"a": 1, "b": 2, "c": 3}),
  403                 (1, 2, 3, (), {}),
  404             )
  405 
  406             self.assertEqual(
  407                 module._call_function("testfunc", func_kwargs={"c": 3, "a": 1, "b": 2}),
  408                 (1, 2, 3, (), {}),
  409             )
  410 
  411             self.assertEqual(
  412                 module._call_function("testfunc", func_kwargs={"b": 2, "a": 1, "c": 3}),
  413                 (1, 2, 3, (), {}),
  414             )
  415 
  416             self.assertEqual(
  417                 module._call_function("testfunc", func_kwargs={"a": 1, "c": 3, "b": 2}),
  418                 (1, 2, 3, (), {}),
  419             )
  420 
  421         with patch.dict(
  422             module.__salt__,
  423             {"testfunc": lambda c, a, b, *args, **kwargs: (a, b, c, args, kwargs)},
  424             clear=True,
  425         ):
  426             self.assertEqual(
  427                 module._call_function(
  428                     "testfunc", func_args=[{"a": 1}, {"b": 2}, {"c": 3}]
  429                 ),
  430                 (1, 2, 3, (), {}),
  431             )
  432             self.assertEqual(
  433                 module._call_function(
  434                     "testfunc", func_args=[{"c": 3}, {"a": 1}, {"b": 2}]
  435                 ),
  436                 (1, 2, 3, (), {}),
  437             )
  438 
  439             self.assertEqual(
  440                 module._call_function("testfunc", func_kwargs={"a": 1, "b": 2, "c": 3}),
  441                 (1, 2, 3, (), {}),
  442             )
  443 
  444             self.assertEqual(
  445                 module._call_function("testfunc", func_kwargs={"c": 3, "a": 1, "b": 2}),
  446                 (1, 2, 3, (), {}),
  447             )
  448 
  449             self.assertEqual(
  450                 module._call_function("testfunc", func_kwargs={"b": 2, "a": 1, "c": 3}),
  451                 (1, 2, 3, (), {}),
  452             )
  453 
  454             self.assertEqual(
  455                 module._call_function("testfunc", func_kwargs={"a": 1, "c": 3, "b": 2}),
  456                 (1, 2, 3, (), {}),
  457             )
  458 
  459     def test_call_function_ordered_args(self):
  460         """
  461         Test _call_function routine when params are not named. Their position should matter.
  462 
  463         :return:
  464         """
  465         with patch.dict(
  466             module.__salt__,
  467             {"testfunc": lambda a, b, c, *args, **kwargs: (a, b, c, args, kwargs)},
  468             clear=True,
  469         ):
  470             self.assertEqual(
  471                 module._call_function("testfunc", func_args=[1, 2, 3]),
  472                 (1, 2, 3, (), {}),
  473             )
  474             self.assertEqual(
  475                 module._call_function("testfunc", func_args=[3, 1, 2]),
  476                 (3, 1, 2, (), {}),
  477             )
  478 
  479     def test_call_function_ordered_and_named_args(self):
  480         """
  481         Test _call_function routine when params are not named. Their position should matter.
  482 
  483         :return:
  484         """
  485         with patch.dict(
  486             module.__salt__,
  487             {"testfunc": lambda a, b, c, *args, **kwargs: (a, b, c, args, kwargs)},
  488             clear=True,
  489         ):
  490             self.assertEqual(
  491                 module._call_function(
  492                     "testfunc", func_args=[1], func_kwargs={"b": 2, "c": 3}
  493                 ),
  494                 (1, 2, 3, (), {}),
  495             )
  496 
  497             self.assertEqual(
  498                 module._call_function(
  499                     "testfunc", func_args=[1, 2], func_kwargs={"c": 3}
  500                 ),
  501                 (1, 2, 3, (), {}),
  502             )