1import os
2
3import salt.modules.file as file_
4import salt.modules.heat as heat
5import salt.modules.win_file as win_file
6import salt.utils.platform
7import salt.utils.win_dacl as dacl
8from tests.support.mixins import LoaderModuleMockMixin
9from tests.support.mock import MagicMock, patch
10from tests.support.runtests import RUNTIME_VARS
11from tests.support.unit import TestCase
12
13
14class MockStacks:
15    """
16    Mock stacks.StackManager
17    """
18
19    def validate(self, **kwargs):
20        """
21        Mock of stacks.StackManager.validate method
22        """
23        self.mock_val_ret = MagicMock()
24        self.mock_val_ret.json.return_value = {"result": "mocked response"}
25        self.mock_validate = MagicMock()
26        self.mock_validate.post.return_value = self.mock_val_ret
27        return self.mock_validate
28
29    def create(self, **kwargs):
30        self.mock_create_ret = MagicMock()
31        self.mock_create_ret.json.return_value = {
32            "result": "mocked create",
33            "fields": kwargs,
34        }
35        self.mock_create = MagicMock()
36        self.mock_create.post.return_value = self.mock_create_ret
37        return self.mock_create
38
39    def update(self, name, **kwargs):
40        self.mock_update_ret = MagicMock()
41        self.mock_update_ret.json.return_value = {
42            "result": "mocked update",
43            "fields": kwargs,
44            "name": name,
45        }
46        self.mock_update = MagicMock()
47        self.mock_update.post.return_value = self.mock_update_ret
48        return self.mock_update
49
50
51class MockClient:
52    """
53    Mock of Client class
54    """
55
56    def __init__(self, profile=None, **conn_args):
57        self.stacks = MockStacks()
58
59
60class HeatTestCase(TestCase, LoaderModuleMockMixin):
61    """
62    Test cases for salt.modules.heat
63    """
64
65    def setup_loader_modules(self):
66        return {
67            heat: {"_auth": MockClient},
68            file_: {
69                "__opts__": {
70                    "hash_type": "sha256",
71                    "cachedir": os.path.join(RUNTIME_VARS.TMP, "rootdir", "cache"),
72                    "test": False,
73                },
74                "__salt__": {
75                    "config.option": MagicMock(
76                        return_value={"obfuscate_templates": False}
77                    ),
78                    "config.backup_mode": MagicMock(return_value=False),
79                },
80            },
81            win_file: {
82                "__utils__": {"dacl.check_perms": salt.utils.win_dacl.check_perms}
83            },
84            dacl: {"__opts__": {"test": False}},
85        }
86
87    def setUp(self):
88        self.patch_check = patch("salt.modules.file.check_perms", file_.check_perms)
89        if salt.utils.platform.is_windows():
90            self.patch_check = patch(
91                "salt.modules.file.check_perms", win_file.check_perms
92            )
93
94    def test_heat_create_stack(self):
95        """
96        Test salt.modules.heat.create_stack method
97        """
98        patch_file = patch.dict(
99            heat.__salt__,
100            {
101                "file.get_managed": file_.get_managed,
102                "file.manage_file": file_.manage_file,
103            },
104        )
105
106        with patch_file, self.patch_check:
107            ret = heat.create_stack(
108                name="mystack",
109                profile="openstack1",
110                template_file=os.path.join(
111                    RUNTIME_VARS.BASE_FILES, "templates", "heat-template.yml"
112                ),
113            )
114        assert ret == {"result": True, "comment": "Created stack 'mystack'."}
115
116    def test_heat_create_stack_environment(self):
117        """
118        Test salt.modules.heat.create_stack method with environment set
119        """
120        patch_file = patch.dict(
121            "salt.modules.heat.__salt__",
122            {
123                "file.get_managed": file_.get_managed,
124                "file.manage_file": file_.manage_file,
125            },
126        )
127        with patch_file, self.patch_check:
128            ret = heat.create_stack(
129                name="mystack",
130                profile="openstack1",
131                environment=os.path.join(
132                    RUNTIME_VARS.BASE_FILES, "templates", "heat-env.yml"
133                ),
134                template_file=os.path.join(
135                    RUNTIME_VARS.BASE_FILES, "templates", "heat-template.yml"
136                ),
137            )
138        assert ret == {"result": True, "comment": "Created stack 'mystack'."}
139
140    def test_heat_create_stack_environment_err(self):
141        """
142        Test salt.modules.heat.create_stack method with environment set
143        and there is an error reading the environment file
144        """
145        patch_file = patch.dict(
146            "salt.modules.heat.__salt__",
147            {
148                "file.get_managed": file_.get_managed,
149                "file.manage_file": MagicMock(
150                    side_effect=[{"result": True}, {"result": False}]
151                ),
152            },
153        )
154        patch_template = patch(
155            "salt.modules.heat._parse_template", MagicMock(return_value=True)
156        )
157        env_file = os.path.join(RUNTIME_VARS.BASE_FILES, "templates", "heat-env.yml")
158        with patch_file, patch_template, self.patch_check:
159            ret = heat.create_stack(
160                name="mystack",
161                profile="openstack1",
162                environment=env_file,
163                template_file=os.path.join(
164                    RUNTIME_VARS.BASE_FILES, "templates", "heat-template.yml"
165                ),
166            )
167        assert ret == {
168            "result": False,
169            "comment": "Can not open environment: {}, ".format(env_file),
170        }
171
172    def test_heat_update_stack(self):
173        """
174        Test salt.modules.heat.update_method method
175        """
176        patch_file = patch.dict(
177            heat.__salt__,
178            {
179                "file.get_managed": file_.get_managed,
180                "file.manage_file": file_.manage_file,
181            },
182        )
183        with patch_file, self.patch_check:
184            ret = heat.update_stack(
185                name="mystack",
186                profile="openstack1",
187                template_file=os.path.join(
188                    RUNTIME_VARS.BASE_FILES, "templates", "heat-template.yml"
189                ),
190            )
191        assert ret == {"result": True, "comment": ("Updated stack 'mystack'.",)}
192
193    def test_heat_update_stack_env(self):
194        """
195        Test salt.modules.heat.update_method method
196        with environment set
197        """
198        patch_file = patch.dict(
199            heat.__salt__,
200            {
201                "file.get_managed": file_.get_managed,
202                "file.manage_file": file_.manage_file,
203            },
204        )
205        with patch_file, self.patch_check:
206            ret = heat.update_stack(
207                name="mystack",
208                profile="openstack1",
209                template_file=os.path.join(
210                    RUNTIME_VARS.BASE_FILES, "templates", "heat-template.yml"
211                ),
212                environment=os.path.join(
213                    RUNTIME_VARS.BASE_FILES, "templates", "heat-env.yml"
214                ),
215            )
216        assert ret == {"result": True, "comment": ("Updated stack 'mystack'.",)}
217
218    def test_heat_update_stack_env_err(self):
219        """
220        Test salt.modules.heat.update_method method
221        with environment set and there is an error
222        reading the environment file
223        """
224        patch_file = patch.dict(
225            heat.__salt__,
226            {
227                "file.get_managed": file_.get_managed,
228                "file.manage_file": MagicMock(
229                    side_effect=[{"result": True}, {"result": False}]
230                ),
231            },
232        )
233        with patch_file, self.patch_check:
234            ret = heat.update_stack(
235                name="mystack",
236                profile="openstack1",
237                template_file=os.path.join(
238                    RUNTIME_VARS.BASE_FILES, "templates", "heat-template.yml"
239                ),
240                environment=os.path.join(
241                    RUNTIME_VARS.BASE_FILES, "templates", "heat-env.yml"
242                ),
243            )
244        assert ret == {
245            "result": False,
246            "comment": "Error parsing template Template format version not found.",
247        }
248