# -*- coding: utf-8 -*- """ unittests for highstate outputter """ # Import Python Libs from __future__ import absolute_import import salt.output.highstate as highstate # Import Salt Libs import salt.utils.stringutils # Import 3rd-party libs from salt.ext import six # Import Salt Testing Libs from tests.support.mixins import LoaderModuleMockMixin from tests.support.unit import TestCase class JsonTestCase(TestCase, LoaderModuleMockMixin): """ Test cases for salt.output.highstate """ def setup_loader_modules(self): return { highstate: { "__opts__": { "extension_modules": "", "optimization_order": [0, 1, 2], "color": False, } } } def setUp(self): self.data = { "data": { "master": { "salt_|-call_sleep_state_|-call_sleep_state_|-state": { "__id__": "call_sleep_state", "__jid__": "20170418153529810135", "__run_num__": 0, "__sls__": "orch.simple", "changes": { "out": "highstate", "ret": { "minion": { "module_|-simple-ping_|-test.ping_|-run": { "__id__": "simple-ping", "__run_num__": 0, "__sls__": "simple-ping", "changes": {"ret": True}, "comment": "Module function test.ping executed", "duration": 56.179, "name": "test.ping", "result": True, "start_time": "15:35:31.282099", } }, "sub_minion": { "module_|-simple-ping_|-test.ping_|-run": { "__id__": "simple-ping", "__run_num__": 0, "__sls__": "simple-ping", "changes": {"ret": True}, "comment": "Module function test.ping executed", "duration": 54.103, "name": "test.ping", "result": True, "start_time": "15:35:31.005606", } }, }, }, "comment": "States ran successfully. Updating sub_minion, minion.", "duration": 1638.047, "name": "call_sleep_state", "result": True, "start_time": "15:35:29.762657", }, "salt_|-cmd_run_example_|-cmd.run_|-function": { "__id__": "cmd_run_example", "__jid__": "20200411195112288850", "__run_num__": 1, "__sls__": "orch.simple", "changes": { "out": "highstate", "ret": {"minion": "file1\nfile2\nfile3"}, }, "comment": "Function ran successfully. Function cmd.run ran on minion.", "duration": 412.397, "name": "cmd.run", "result": True, "start_time": "21:51:12.185868", }, } }, "outputter": "highstate", "retcode": 0, } self.addCleanup(delattr, self, "data") def test_default_output(self): ret = highstate.output(self.data) self.assertIn("Succeeded: 1 (changed=1)", ret) self.assertIn("Failed: 0", ret) self.assertIn("Total states run: 1", ret) self.assertIn(" file2", ret) def test_output_comment_is_not_unicode(self): entry = None for key in ( "data", "master", "salt_|-call_sleep_state_|-call_sleep_state_|-state", "changes", "ret", "minion", "module_|-simple-ping_|-test.ping_|-run", ): if entry is None: entry = self.data[key] continue entry = entry[key] if six.PY2: entry["comment"] = salt.utils.stringutils.to_unicode(entry["comment"]) else: entry["comment"] = salt.utils.stringutils.to_bytes(entry["comment"]) ret = highstate.output(self.data) self.assertIn("Succeeded: 1 (changed=1)", ret) self.assertIn("Failed: 0", ret) self.assertIn("Total states run: 1", ret) self.assertIn(" file2", ret) # this should all pass the above tests class JsonNestedTestCase(TestCase, LoaderModuleMockMixin): """ Test cases for nested salt.output.highstate (ie orchestrations calling other orchs) """ def setup_loader_modules(self): return { highstate: { "__opts__": { "extension_modules": "", "color": False, "optimization_order": [0, 1, 2], } } } def setUp(self): self.data = { "outputter": "highstate", "data": { "local_master": { "salt_|-nested_|-state.orchestrate_|-runner": { "comment": "Runner function 'state.orchestrate' executed.", "name": "state.orchestrate", "__orchestration__": True, "start_time": "09:22:53.158742", "result": True, "duration": 980.694, "__run_num__": 0, "__jid__": "20180326092253538853", "__sls__": "orch.test.nested", "changes": { "return": { "outputter": "highstate", "data": { "local_master": { "test_|-always-passes-with-changes_|-oinaosf_|-succeed_with_changes": { "comment": "Success!", "name": "oinaosf", "start_time": "09:22:54.128415", "result": True, "duration": 0.437, "__run_num__": 0, "__sls__": "orch.test.changes", "changes": { "testing": { "new": "Something pretended to change", "old": "Unchanged", } }, "__id__": "always-passes-with-changes", }, "test_|-always-passes_|-fasdfasddfasdfoo_|-succeed_without_changes": { "comment": "Success!", "name": "fasdfasddfasdfoo", "start_time": "09:22:54.128986", "result": True, "duration": 0.25, "__run_num__": 1, "__sls__": "orch.test.changes", "changes": {}, "__id__": "always-passes", }, } }, "retcode": 0, } }, "__id__": "nested", } } }, "retcode": 0, } self.addCleanup(delattr, self, "data") def test_nested_output(self): ret = highstate.output(self.data) self.assertIn("Succeeded: 1 (changed=1)", ret) self.assertIn("Failed: 0", ret) self.assertIn("Total states run: 1", ret) # the whitespace is relevant in this case, it is testing that it is nested self.assertIn(" ID: always-passes-with-changes", ret) self.assertIn(" Started: 09:22:54.128415", ret) self.assertIn(" Succeeded: 2 (changed=1)", ret) self.assertIn(" Failed: 0", ret) self.assertIn(" Total states run: 2", ret)