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