xref: /unit/test/test_configuration.py (revision 1596:b7e2d4d92624)
1import pytest
2
3from unit.control import TestControl
4from conftest import skip_alert
5
6
7class TestConfiguration(TestControl):
8    prerequisites = {'modules': {'python': 'any'}}
9
10    def test_json_empty(self):
11        assert 'error' in self.conf(''), 'empty'
12
13    def test_json_leading_zero(self):
14        assert 'error' in self.conf('00'), 'leading zero'
15
16    def test_json_unicode(self):
17        assert 'success' in self.conf(
18            b"""
19            {
20                "ap\u0070": {
21                    "type": "\u0070ython",
22                    "processes": { "spare": 0 },
23                    "path": "\u002Fapp",
24                    "module": "wsgi"
25                }
26            }
27            """,
28            'applications',
29        ), 'unicode'
30
31        assert self.conf_get('applications') == {
32            "app": {
33                "type": "python",
34                "processes": {"spare": 0},
35                "path": "/app",
36                "module": "wsgi",
37            }
38        }, 'unicode get'
39
40    def test_json_unicode_2(self):
41        assert 'success' in self.conf(
42            {
43                "приложение": {
44                    "type": "python",
45                    "processes": {"spare": 0},
46                    "path": "/app",
47                    "module": "wsgi",
48                }
49            },
50            'applications',
51        ), 'unicode 2'
52
53        assert 'приложение' in self.conf_get('applications'), 'unicode 2 get'
54
55    def test_json_unicode_number(self):
56        assert 'error' in self.conf(
57            b"""
58            {
59                "app": {
60                    "type": "python",
61                    "processes": { "spare": \u0030 },
62                    "path": "/app",
63                    "module": "wsgi"
64                }
65            }
66            """,
67            'applications',
68        ), 'unicode number'
69
70    def test_json_utf8_bom(self):
71        assert 'success' in self.conf(
72            b"""\xEF\xBB\xBF
73            {
74                "app": {
75                    "type": "python",
76                    "processes": {"spare": 0},
77                    "path": "/app",
78                    "module": "wsgi"
79                }
80            }
81            """,
82            'applications',
83        ), 'UTF-8 BOM'
84
85    def test_json_comment_single_line(self):
86        assert 'success' in self.conf(
87            b"""
88            // this is bridge
89            {
90                "//app": {
91                    "type": "python", // end line
92                    "processes": {"spare": 0},
93                    // inside of block
94                    "path": "/app",
95                    "module": "wsgi"
96                }
97                // double //
98            }
99            // end of json \xEF\t
100            """,
101            'applications',
102        ), 'single line comments'
103
104    def test_json_comment_multi_line(self):
105        assert 'success' in self.conf(
106            b"""
107            /* this is bridge */
108            {
109                "/*app": {
110                /**
111                 * multiple lines
112                 **/
113                    "type": "python",
114                    "processes": /* inline */ {"spare": 0},
115                    "path": "/app",
116                    "module": "wsgi"
117                    /*
118                    // end of block */
119                }
120                /* blah * / blah /* blah */
121            }
122            /* end of json \xEF\t\b */
123            """,
124            'applications',
125        ), 'multi line comments'
126
127    def test_json_comment_invalid(self):
128        assert 'error' in self.conf(b'/{}', 'applications'), 'slash'
129        assert 'error' in self.conf(b'//{}', 'applications'), 'comment'
130        assert 'error' in self.conf(b'{} /', 'applications'), 'slash end'
131        assert 'error' in self.conf(b'/*{}', 'applications'), 'slash star'
132        assert 'error' in self.conf(b'{} /*', 'applications'), 'slash star end'
133
134    def test_applications_open_brace(self):
135        assert 'error' in self.conf('{', 'applications'), 'open brace'
136
137    def test_applications_string(self):
138        assert 'error' in self.conf('"{}"', 'applications'), 'string'
139
140    @pytest.mark.skip('not yet, unsafe')
141    def test_applications_type_only(self):
142        assert 'error' in self.conf(
143            {"app": {"type": "python"}}, 'applications'
144        ), 'type only'
145
146    def test_applications_miss_quote(self):
147        assert 'error' in self.conf(
148            """
149            {
150                app": {
151                    "type": "python",
152                    "processes": { "spare": 0 },
153                    "path": "/app",
154                    "module": "wsgi"
155                }
156            }
157            """,
158            'applications',
159        ), 'miss quote'
160
161    def test_applications_miss_colon(self):
162        assert 'error' in self.conf(
163            """
164            {
165                "app" {
166                    "type": "python",
167                    "processes": { "spare": 0 },
168                    "path": "/app",
169                    "module": "wsgi"
170                }
171            }
172            """,
173            'applications',
174        ), 'miss colon'
175
176    def test_applications_miss_comma(self):
177        assert 'error' in self.conf(
178            """
179            {
180                "app": {
181                    "type": "python"
182                    "processes": { "spare": 0 },
183                    "path": "/app",
184                    "module": "wsgi"
185                }
186            }
187            """,
188            'applications',
189        ), 'miss comma'
190
191    def test_applications_skip_spaces(self):
192        assert 'success' in self.conf(
193            b'{ \n\r\t}', 'applications'
194        ), 'skip spaces'
195
196    def test_applications_relative_path(self):
197        assert 'success' in self.conf(
198            {
199                "app": {
200                    "type": "python",
201                    "processes": {"spare": 0},
202                    "path": "../app",
203                    "module": "wsgi",
204                }
205            },
206            'applications',
207        ), 'relative path'
208
209    @pytest.mark.skip('not yet, unsafe')
210    def test_listeners_empty(self):
211        assert 'error' in self.conf(
212            {"*:7080": {}}, 'listeners'
213        ), 'listener empty'
214
215    def test_listeners_no_app(self):
216        assert 'error' in self.conf(
217            {"*:7080": {"pass": "applications/app"}}, 'listeners'
218        ), 'listeners no app'
219
220    def test_listeners_wildcard(self):
221        assert 'success' in self.conf(
222            {
223                "listeners": {"*:7080": {"pass": "applications/app"}},
224                "applications": {
225                    "app": {
226                        "type": "python",
227                        "processes": {"spare": 0},
228                        "path": "/app",
229                        "module": "wsgi",
230                    }
231                },
232            }
233        ), 'listeners wildcard'
234
235    def test_listeners_explicit(self):
236        assert 'success' in self.conf(
237            {
238                "listeners": {"127.0.0.1:7080": {"pass": "applications/app"}},
239                "applications": {
240                    "app": {
241                        "type": "python",
242                        "processes": {"spare": 0},
243                        "path": "/app",
244                        "module": "wsgi",
245                    }
246                },
247            }
248        ), 'explicit'
249
250    def test_listeners_explicit_ipv6(self):
251        assert 'success' in self.conf(
252            {
253                "listeners": {"[::1]:7080": {"pass": "applications/app"}},
254                "applications": {
255                    "app": {
256                        "type": "python",
257                        "processes": {"spare": 0},
258                        "path": "/app",
259                        "module": "wsgi",
260                    }
261                },
262            }
263        ), 'explicit ipv6'
264
265    @pytest.mark.skip('not yet, unsafe')
266    def test_listeners_no_port(self):
267        assert 'error' in self.conf(
268            {
269                "listeners": {"127.0.0.1": {"pass": "applications/app"}},
270                "applications": {
271                    "app": {
272                        "type": "python",
273                        "processes": {"spare": 0},
274                        "path": "/app",
275                        "module": "wsgi",
276                    }
277                },
278            }
279        ), 'no port'
280
281    def test_json_application_name_large(self):
282        name = "X" * 1024 * 1024
283
284        assert 'success' in self.conf(
285            {
286                "listeners": {"*:7080": {"pass": "applications/" + name}},
287                "applications": {
288                    name: {
289                        "type": "python",
290                        "processes": {"spare": 0},
291                        "path": "/app",
292                        "module": "wsgi",
293                    }
294                },
295            }
296        )
297
298    @pytest.mark.skip('not yet')
299    def test_json_application_many(self):
300        apps = 999
301
302        conf = {
303            "applications": {
304                "app-"
305                + str(a): {
306                    "type": "python",
307                    "processes": {"spare": 0},
308                    "path": "/app",
309                    "module": "wsgi",
310                }
311                for a in range(apps)
312            },
313            "listeners": {
314                "*:" + str(7000 + a): {"pass": "applications/app-" + str(a)}
315                for a in range(apps)
316            },
317        }
318
319        assert 'success' in self.conf(conf)
320
321    def test_json_application_many2(self):
322        conf = {
323            "applications": {
324                "app-"
325                + str(a): {
326                    "type": "python",
327                    "processes": {"spare": 0},
328                    "path": "/app",
329                    "module": "wsgi",
330                }
331                # Larger number of applications can cause test fail with default
332                # open files limit due to the lack of file descriptors.
333                for a in range(100)
334            },
335            "listeners": {"*:7080": {"pass": "applications/app-1"}},
336        }
337
338        assert 'success' in self.conf(conf)
339
340    def test_unprivileged_user_error(self, is_su):
341        skip_alert(r'cannot set user "root"', r'failed to apply new conf')
342        if is_su:
343            pytest.skip('unprivileged tests')
344
345        assert 'error' in self.conf(
346            {
347                "app": {
348                    "type": "external",
349                    "processes": 1,
350                    "executable": "/app",
351                    "user": "root",
352                }
353            },
354            'applications',
355        ), 'setting user'
356