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