1"""
2unittests for highstate outputter
3"""
4
5
6import salt.output.highstate as highstate
7import salt.utils.stringutils
8from tests.support.mixins import LoaderModuleMockMixin
9from tests.support.unit import TestCase
10
11
12class JsonTestCase(TestCase, LoaderModuleMockMixin):
13    """
14    Test cases for salt.output.highstate
15    """
16
17    def setup_loader_modules(self):
18        return {
19            highstate: {
20                "__opts__": {
21                    "extension_modules": "",
22                    "optimization_order": [0, 1, 2],
23                    "color": False,
24                }
25            }
26        }
27
28    def setUp(self):
29        self.data = {
30            "data": {
31                "master": {
32                    "salt_|-call_sleep_state_|-call_sleep_state_|-state": {
33                        "__id__": "call_sleep_state",
34                        "__jid__": "20170418153529810135",
35                        "__run_num__": 0,
36                        "__sls__": "orch.simple",
37                        "changes": {
38                            "out": "highstate",
39                            "ret": {
40                                "minion": {
41                                    "module_|-simple-ping_|-test.ping_|-run": {
42                                        "__id__": "simple-ping",
43                                        "__run_num__": 0,
44                                        "__sls__": "simple-ping",
45                                        "changes": {"ret": True},
46                                        "comment": "Module function test.ping executed",
47                                        "duration": 56.179,
48                                        "name": "test.ping",
49                                        "result": True,
50                                        "start_time": "15:35:31.282099",
51                                    }
52                                },
53                                "sub_minion": {
54                                    "module_|-simple-ping_|-test.ping_|-run": {
55                                        "__id__": "simple-ping",
56                                        "__run_num__": 0,
57                                        "__sls__": "simple-ping",
58                                        "changes": {"ret": True},
59                                        "comment": "Module function test.ping executed",
60                                        "duration": 54.103,
61                                        "name": "test.ping",
62                                        "result": True,
63                                        "start_time": "15:35:31.005606",
64                                    }
65                                },
66                            },
67                        },
68                        "comment": (
69                            "States ran successfully. Updating sub_minion, minion."
70                        ),
71                        "duration": 1638.047,
72                        "name": "call_sleep_state",
73                        "result": True,
74                        "start_time": "15:35:29.762657",
75                    },
76                    "salt_|-cmd_run_example_|-cmd.run_|-function": {
77                        "__id__": "cmd_run_example",
78                        "__jid__": "20200411195112288850",
79                        "__run_num__": 1,
80                        "__sls__": "orch.simple",
81                        "changes": {
82                            "out": "highstate",
83                            "ret": {"minion": "file1\nfile2\nfile3"},
84                        },
85                        "comment": (
86                            "Function ran successfully. Function cmd.run ran on minion."
87                        ),
88                        "duration": 412.397,
89                        "name": "cmd.run",
90                        "result": True,
91                        "start_time": "21:51:12.185868",
92                    },
93                }
94            },
95            "outputter": "highstate",
96            "retcode": 0,
97        }
98        self.addCleanup(delattr, self, "data")
99
100    def test_default_output(self):
101        ret = highstate.output(self.data)
102        self.assertIn("Succeeded: 1 (changed=1)", ret)
103        self.assertIn("Failed:    0", ret)
104        self.assertIn("Total states run:     1", ret)
105        self.assertIn("                  file2", ret)
106
107    def test_output_comment_is_not_unicode(self):
108        entry = None
109        for key in (
110            "data",
111            "master",
112            "salt_|-call_sleep_state_|-call_sleep_state_|-state",
113            "changes",
114            "ret",
115            "minion",
116            "module_|-simple-ping_|-test.ping_|-run",
117        ):
118            if entry is None:
119                entry = self.data[key]
120                continue
121            entry = entry[key]
122        entry["comment"] = salt.utils.stringutils.to_bytes(entry["comment"])
123        ret = highstate.output(self.data)
124        self.assertIn("Succeeded: 1 (changed=1)", ret)
125        self.assertIn("Failed:    0", ret)
126        self.assertIn("Total states run:     1", ret)
127        self.assertIn("                  file2", ret)
128
129
130# this should all pass the above tests
131class JsonNestedTestCase(TestCase, LoaderModuleMockMixin):
132    """
133    Test cases for nested salt.output.highstate (ie orchestrations calling other orchs)
134    """
135
136    def setup_loader_modules(self):
137        return {
138            highstate: {
139                "__opts__": {
140                    "extension_modules": "",
141                    "color": False,
142                    "state_output_profile": True,
143                    "optimization_order": [0, 1, 2],
144                }
145            }
146        }
147
148    def setUp(self):
149        self.data = {
150            "outputter": "highstate",
151            "data": {
152                "local_master": {
153                    "salt_|-nested_|-state.orchestrate_|-runner": {
154                        "comment": "Runner function 'state.orchestrate' executed.",
155                        "name": "state.orchestrate",
156                        "__orchestration__": True,
157                        "start_time": "09:22:53.158742",
158                        "result": True,
159                        "duration": 980.694,
160                        "__run_num__": 0,
161                        "__jid__": "20180326092253538853",
162                        "__sls__": "orch.test.nested",
163                        "changes": {
164                            "return": {
165                                "outputter": "highstate",
166                                "data": {
167                                    "local_master": {
168                                        "test_|-always-passes-with-changes_|-oinaosf_|-succeed_with_changes": {
169                                            "comment": "Success!",
170                                            "name": "oinaosf",
171                                            "start_time": "09:22:54.128415",
172                                            "result": True,
173                                            "duration": 0.437,
174                                            "__run_num__": 0,
175                                            "__sls__": "orch.test.changes",
176                                            "changes": {
177                                                "testing": {
178                                                    "new": (
179                                                        "Something pretended to change"
180                                                    ),
181                                                    "old": "Unchanged",
182                                                }
183                                            },
184                                            "__id__": "always-passes-with-changes",
185                                        },
186                                        "test_|-always-passes_|-fasdfasddfasdfoo_|-succeed_without_changes": {
187                                            "comment": "Success!",
188                                            "name": "fasdfasddfasdfoo",
189                                            "start_time": "09:22:54.128986",
190                                            "result": True,
191                                            "duration": 0.25,
192                                            "__run_num__": 1,
193                                            "__sls__": "orch.test.changes",
194                                            "changes": {},
195                                            "__id__": "always-passes",
196                                        },
197                                    }
198                                },
199                                "retcode": 0,
200                            }
201                        },
202                        "__id__": "nested",
203                    }
204                }
205            },
206            "retcode": 0,
207        }
208
209        self.addCleanup(delattr, self, "data")
210
211    def test_nested_output(self):
212        ret = highstate.output(self.data)
213        self.assertIn("Succeeded: 1 (changed=1)", ret)
214        self.assertIn("Failed:    0", ret)
215        self.assertIn("Total states run:     1", ret)
216
217        # the whitespace is relevant in this case, it is testing that it is nested
218        self.assertIn("                        ID: always-passes-with-changes", ret)
219        self.assertIn("                   Started: 09:22:54.128415", ret)
220        self.assertIn("              Succeeded: 2 (changed=1)", ret)
221        self.assertIn("              Failed:    0", ret)
222        self.assertIn("              Total states run:     2", ret)
223