1"""
2    :codeauthor: Jayesh Kariya <jayeshk@saltstack.com>
3"""
4
5import urllib.error
6
7import salt.modules.apache as apache
8from salt.utils.odict import OrderedDict
9from tests.support.mixins import LoaderModuleMockMixin
10from tests.support.mock import MagicMock, mock_open, patch
11from tests.support.unit import TestCase
12
13
14class ApacheTestCase(TestCase, LoaderModuleMockMixin):
15    """
16    Test cases for salt.modules.apache
17    """
18
19    def setup_loader_modules(self):
20        return {apache: {}}
21
22    # 'version' function tests: 1
23    def test_version(self):
24        """
25        Test if return server version (``apachectl -v``)
26        """
27        with patch(
28            "salt.modules.apache._detect_os", MagicMock(return_value="apachectl")
29        ):
30            mock = MagicMock(return_value="Server version: Apache/2.4.7")
31            with patch.dict(apache.__salt__, {"cmd.run": mock}):
32                assert apache.version() == "Apache/2.4.7"
33
34    # 'fullversion' function tests: 1
35
36    def test_fullversion(self):
37        """
38        Test if return server version (``apachectl -V``)
39        """
40        with patch(
41            "salt.modules.apache._detect_os", MagicMock(return_value="apachectl")
42        ):
43            mock = MagicMock(return_value="Server version: Apache/2.4.7")
44            with patch.dict(apache.__salt__, {"cmd.run": mock}):
45                assert apache.fullversion() == {
46                    "compiled_with": [],
47                    "server_version": "Apache/2.4.7",
48                }
49
50    # 'modules' function tests: 1
51
52    def test_modules(self):
53        """
54        Test if return list of static and shared modules
55        """
56        with patch(
57            "salt.modules.apache._detect_os", MagicMock(return_value="apachectl")
58        ):
59            mock = MagicMock(
60                return_value=(
61                    "unixd_module (static)\n                             "
62                    " access_compat_module (shared)"
63                )
64            )
65            with patch.dict(apache.__salt__, {"cmd.run": mock}):
66                assert apache.modules() == {
67                    "shared": ["access_compat_module"],
68                    "static": ["unixd_module"],
69                }
70
71    # 'servermods' function tests: 1
72
73    def test_servermods(self):
74        """
75        Test if return list of modules compiled into the server
76        """
77        with patch(
78            "salt.modules.apache._detect_os", MagicMock(return_value="apachectl")
79        ):
80            mock = MagicMock(return_value="core.c\nmod_so.c")
81            with patch.dict(apache.__salt__, {"cmd.run": mock}):
82                assert apache.servermods() == ["core.c", "mod_so.c"]
83
84    # 'directives' function tests: 1
85
86    def test_directives(self):
87        """
88        Test if return list of directives
89        """
90        with patch(
91            "salt.modules.apache._detect_os", MagicMock(return_value="apachectl")
92        ):
93            mock = MagicMock(return_value="Salt")
94            with patch.dict(apache.__salt__, {"cmd.run": mock}):
95                assert apache.directives() == {"Salt": ""}
96
97    # 'vhosts' function tests: 1
98
99    def test_vhosts(self):
100        """
101        Test if it shows the virtualhost settings
102        """
103        with patch(
104            "salt.modules.apache._detect_os", MagicMock(return_value="apachectl")
105        ):
106            mock = MagicMock(return_value="")
107            with patch.dict(apache.__salt__, {"cmd.run": mock}):
108                assert apache.vhosts() == {}
109
110    # 'signal' function tests: 2
111
112    def test_signal(self):
113        """
114        Test if return no signal for httpd
115        """
116        with patch(
117            "salt.modules.apache._detect_os", MagicMock(return_value="apachectl")
118        ):
119            mock = MagicMock(return_value="")
120            with patch.dict(apache.__salt__, {"cmd.run": mock}):
121                assert apache.signal(None) is None
122
123    def test_signal_args(self):
124        """
125        Test if return httpd signal to start, restart, or stop.
126        """
127        with patch(
128            "salt.modules.apache._detect_os", MagicMock(return_value="apachectl")
129        ):
130            ret = 'Command: "apachectl -k start" completed successfully!'
131            mock = MagicMock(return_value={"retcode": 1, "stderr": "", "stdout": ""})
132            with patch.dict(apache.__salt__, {"cmd.run_all": mock}):
133                assert apache.signal("start") == ret
134
135            mock = MagicMock(
136                return_value={"retcode": 1, "stderr": "Syntax OK", "stdout": ""}
137            )
138            with patch.dict(apache.__salt__, {"cmd.run_all": mock}):
139                assert apache.signal("start") == "Syntax OK"
140
141            mock = MagicMock(
142                return_value={"retcode": 0, "stderr": "Syntax OK", "stdout": ""}
143            )
144            with patch.dict(apache.__salt__, {"cmd.run_all": mock}):
145                assert apache.signal("start") == "Syntax OK"
146
147            mock = MagicMock(
148                return_value={"retcode": 1, "stderr": "", "stdout": "Salt"}
149            )
150            with patch.dict(apache.__salt__, {"cmd.run_all": mock}):
151                assert apache.signal("start") == "Salt"
152
153    # 'useradd' function tests: 1
154
155    def test_useradd(self):
156        """
157        Test if it add HTTP user using the ``htpasswd`` command
158        """
159        mock = MagicMock(return_value=True)
160        with patch.dict(apache.__salt__, {"webutil.useradd": mock}):
161            assert apache.useradd("htpasswd", "salt", "badpassword") is True
162
163    # 'userdel' function tests: 1
164
165    def test_userdel(self):
166        """
167        Test if it delete HTTP user using the ``htpasswd`` file
168        """
169        mock = MagicMock(return_value=True)
170        with patch.dict(apache.__salt__, {"webutil.userdel": mock}):
171            assert apache.userdel("htpasswd", "salt") is True
172
173    # 'server_status' function tests: 2
174
175    def test_server_status(self):
176        """
177        Test if return get information from the Apache server-status
178        """
179        with patch("salt.modules.apache.server_status", MagicMock(return_value={})):
180            mock = MagicMock(return_value="")
181            with patch.dict(apache.__salt__, {"config.get": mock}):
182                assert apache.server_status() == {}
183
184    def test_server_status_error(self):
185        """
186        Test if return get error from the Apache server-status
187        """
188        mock = MagicMock(side_effect=urllib.error.URLError("error"))
189        with patch("urllib.request.urlopen", mock):
190            mock = MagicMock(return_value="")
191            with patch.dict(apache.__salt__, {"config.get": mock}):
192                assert apache.server_status() == "error"
193
194    # 'config' function tests: 1
195
196    def test_config(self):
197        """
198        Test if it create VirtualHost configuration files
199        """
200        with patch(
201            "salt.modules.apache._parse_config", MagicMock(return_value="Listen 22")
202        ):
203            with patch("salt.utils.files.fopen", mock_open()):
204                assert apache.config("/ports.conf", [{"Listen": "22"}]) == "Listen 22"
205
206    # '_parse_config' function tests: 2
207
208    def test__parse_config_dict(self):
209        """
210        Test parsing function which creates configs from dict like (legacy way):
211            - VirtualHost:
212              this: '*:80'
213              ServerName: website.com
214              ServerAlias:
215                - www
216                - dev
217              Directory:
218                  this: /var/www/vhosts/website.com
219                  Order: Deny,Allow
220                  Allow from:
221                    - 127.0.0.1
222                    - 192.168.100.0/24
223
224        """
225        data_in = OrderedDict(
226            [
227                (
228                    "Directory",
229                    OrderedDict(
230                        [
231                            ("this", "/var/www/vhosts/website.com"),
232                            ("Order", "Deny,Allow"),
233                            ("Allow from", ["127.0.0.1", "192.168.100.0/24"]),
234                        ]
235                    ),
236                ),
237                ("this", "*:80"),
238                ("ServerName", "website.com"),
239                ("ServerAlias", ["www", "dev"]),
240            ]
241        )
242        dataout = (
243            "<VirtualHost *:80>\n"
244            "<Directory /var/www/vhosts/website.com>\n"
245            "Order Deny,Allow\n"
246            "Allow from 127.0.0.1\n"
247            "Allow from 192.168.100.0/24\n\n"
248            "</Directory>\n\n"
249            "ServerName website.com\n"
250            "ServerAlias www\n"
251            "ServerAlias dev\n\n"
252            "</VirtualHost>\n"
253        )
254        # pylint: disable=protected-access
255        parse = apache._parse_config(data_in, "VirtualHost")
256        assert parse == dataout
257
258    def test__parse_config_list(self):
259        """
260        Test parsing function which creates configs from variable structure (list of dicts or
261        list of dicts of dicts/lists) like:
262            - VirtualHost:
263              - this: '*:80'
264              - ServerName: website.com
265              - ServerAlias:
266                - www
267                - dev
268              - Directory:
269                  this: /var/www/vhosts/website.com
270                  Order: Deny,Allow
271                  Allow from:
272                    - 127.0.0.1
273                    - 192.168.100.0/24
274              - Directory:
275                - this: /var/www/vhosts/website.com/private
276                - Order: Deny,Allow
277                - Allow from:
278                  - 127.0.0.1
279                  - 192.168.100.0/24
280                - If:
281                    this: some condition
282                    do: something
283        """
284        data_in = [
285            OrderedDict(
286                [
287                    ("ServerName", "website.com"),
288                    ("ServerAlias", ["www", "dev"]),
289                    (
290                        "Directory",
291                        [
292                            OrderedDict(
293                                [
294                                    ("this", "/var/www/vhosts/website.com/private"),
295                                    ("Order", "Deny,Allow"),
296                                    ("Allow from", ["127.0.0.1", "192.168.100.0/24"]),
297                                    (
298                                        "If",
299                                        {"this": "some condition", "do": "something"},
300                                    ),
301                                ]
302                            )
303                        ],
304                    ),
305                    ("this", "*:80"),
306                ]
307            )
308        ]
309        dataout = (
310            "<VirtualHost *:80>\n"
311            "ServerName website.com\n"
312            "ServerAlias www\n"
313            "ServerAlias dev\n\n"
314            "<Directory /var/www/vhosts/website.com/private>\n"
315            "Order Deny,Allow\n"
316            "Allow from 127.0.0.1\n"
317            "Allow from 192.168.100.0/24\n\n"
318            "<If some condition>\n"
319            "do something\n"
320            "</If>\n\n"
321            "</Directory>\n\n"
322            "</VirtualHost>\n"
323        )
324        # pylint: disable=protected-access
325        parse = apache._parse_config(data_in, "VirtualHost")
326        assert parse == dataout
327