xref: /unit/test/test_settings.py (revision 1971:3410f9d2a662)
1import re
2import socket
3import time
4
5import pytest
6from unit.applications.lang.python import TestApplicationPython
7from unit.utils import sysctl
8
9
10class TestSettings(TestApplicationPython):
11    prerequisites = {'modules': {'python': 'any'}}
12
13    def test_settings_header_read_timeout(self):
14        self.load('empty')
15
16        def req():
17            (resp, sock) = self.http(
18                b"""GET / HTTP/1.1
19""",
20                start=True,
21                read_timeout=1,
22                raw=True,
23            )
24
25            time.sleep(3)
26
27            return self.http(
28                b"""Host: localhost
29Connection: close
30
31    """,
32                sock=sock,
33                raw=True,
34            )
35
36        assert 'success' in self.conf(
37            {'http': {'header_read_timeout': 2}}, 'settings'
38        )
39        assert req()['status'] == 408, 'status header read timeout'
40
41        assert 'success' in self.conf(
42            {'http': {'header_read_timeout': 7}}, 'settings'
43        )
44        assert req()['status'] == 200, 'status header read timeout 2'
45
46    def test_settings_header_read_timeout_update(self):
47        self.load('empty')
48
49        assert 'success' in self.conf(
50            {'http': {'header_read_timeout': 4}}, 'settings'
51        )
52
53        (resp, sock) = self.http(
54            b"""GET / HTTP/1.1
55""",
56            start=True,
57            raw=True,
58            no_recv=True,
59        )
60
61        time.sleep(2)
62
63        (resp, sock) = self.http(
64            b"""Host: localhost
65""",
66            start=True,
67            sock=sock,
68            raw=True,
69            no_recv=True,
70        )
71
72        time.sleep(2)
73
74        (resp, sock) = self.http(
75            b"""X-Blah: blah
76""",
77            start=True,
78            sock=sock,
79            read_timeout=1,
80            raw=True,
81        )
82
83        if len(resp) != 0:
84            sock.close()
85
86        else:
87            time.sleep(2)
88
89            resp = self.http(
90                b"""Connection: close
91
92""",
93                sock=sock,
94                raw=True,
95            )
96
97        assert resp['status'] == 408, 'status header read timeout update'
98
99    def test_settings_body_read_timeout(self):
100        self.load('empty')
101
102        def req():
103            (resp, sock) = self.http(
104                b"""POST / HTTP/1.1
105Host: localhost
106Content-Length: 10
107Connection: close
108
109""",
110                start=True,
111                raw_resp=True,
112                read_timeout=1,
113                raw=True,
114            )
115
116            time.sleep(3)
117
118            return self.http(b"""0123456789""", sock=sock, raw=True)
119
120        assert 'success' in self.conf(
121            {'http': {'body_read_timeout': 2}}, 'settings'
122        )
123        assert req()['status'] == 408, 'status body read timeout'
124
125        assert 'success' in self.conf(
126            {'http': {'body_read_timeout': 7}}, 'settings'
127        )
128        assert req()['status'] == 200, 'status body read timeout 2'
129
130    def test_settings_body_read_timeout_update(self):
131        self.load('empty')
132
133        assert 'success' in self.conf(
134            {'http': {'body_read_timeout': 4}}, 'settings'
135        )
136
137        (resp, sock) = self.http(
138            b"""POST / HTTP/1.1
139Host: localhost
140Content-Length: 10
141Connection: close
142
143""",
144            start=True,
145            read_timeout=1,
146            raw=True,
147        )
148
149        time.sleep(2)
150
151        (resp, sock) = self.http(
152            b"""012""", start=True, sock=sock, read_timeout=1, raw=True
153        )
154
155        time.sleep(2)
156
157        (resp, sock) = self.http(
158            b"""345""", start=True, sock=sock, read_timeout=1, raw=True
159        )
160
161        time.sleep(2)
162
163        resp = self.http(b"""6789""", sock=sock, raw=True)
164
165        assert resp['status'] == 200, 'status body read timeout update'
166
167    def test_settings_send_timeout(self, temp_dir):
168        self.load('body_generate')
169
170        def req(addr, data_len):
171            sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
172            sock.connect(addr)
173
174            req = (
175                """GET / HTTP/1.1
176Host: localhost
177X-Length: %d
178Connection: close
179
180"""
181                % data_len
182            )
183
184            sock.sendall(req.encode())
185
186            data = sock.recv(16).decode()
187
188            time.sleep(3)
189
190            data += self.recvall(sock).decode()
191
192            sock.close()
193
194            return data
195
196        sysctl_out = sysctl()
197        values = re.findall(
198            r'net.core.[rw]mem_(?:max|default).*?(\d+)', sysctl_out
199        )
200        values = [int(v) for v in values]
201
202        data_len = 1048576 if len(values) == 0 else 10 * max(values)
203
204        addr = temp_dir + '/sock'
205
206        assert 'success' in self.conf(
207            {"unix:" + addr: {'application': 'body_generate'}}, 'listeners'
208        )
209
210        assert 'success' in self.conf(
211            {'http': {'send_timeout': 1}}, 'settings'
212        )
213
214        data = req(addr, data_len)
215        assert re.search(r'200 OK', data), 'send timeout status'
216        assert len(data) < data_len, 'send timeout data '
217
218        self.conf({'http': {'send_timeout': 7}}, 'settings')
219
220        data = req(addr, data_len)
221        assert re.search(r'200 OK', data), 'send timeout status  2'
222        assert len(data) > data_len, 'send timeout data 2'
223
224    def test_settings_idle_timeout(self):
225        self.load('empty')
226
227        def req():
228            (resp, sock) = self.get(
229                headers={'Host': 'localhost', 'Connection': 'keep-alive'},
230                start=True,
231                read_timeout=1,
232            )
233
234            time.sleep(3)
235
236            return self.get(sock=sock)
237
238        assert self.get()['status'] == 200, 'init'
239
240        assert 'success' in self.conf(
241            {'http': {'idle_timeout': 2}}, 'settings'
242        )
243        assert req()['status'] == 408, 'status idle timeout'
244
245        assert 'success' in self.conf(
246            {'http': {'idle_timeout': 7}}, 'settings'
247        )
248        assert req()['status'] == 200, 'status idle timeout 2'
249
250    def test_settings_idle_timeout_2(self):
251        self.load('empty')
252
253        def req():
254            _, sock = self.http(b'', start=True, raw=True, no_recv=True)
255
256            time.sleep(3)
257
258            return self.get(sock=sock)
259
260        assert self.get()['status'] == 200, 'init'
261
262        assert 'success' in self.conf(
263            {'http': {'idle_timeout': 1}}, 'settings'
264        )
265        assert req()['status'] == 408, 'status idle timeout'
266
267        assert 'success' in self.conf(
268            {'http': {'idle_timeout': 7}}, 'settings'
269        )
270        assert req()['status'] == 200, 'status idle timeout 2'
271
272    def test_settings_max_body_size(self):
273        self.load('empty')
274
275        assert 'success' in self.conf(
276            {'http': {'max_body_size': 5}}, 'settings'
277        )
278
279        assert self.post(body='01234')['status'] == 200, 'status size'
280        assert self.post(body='012345')['status'] == 413, 'status size max'
281
282    def test_settings_max_body_size_large(self):
283        self.load('mirror')
284
285        assert 'success' in self.conf(
286            {'http': {'max_body_size': 32 * 1024 * 1024}}, 'settings'
287        )
288
289        body = '0123456789abcdef' * 4 * 64 * 1024
290        resp = self.post(body=body, read_buffer_size=1024 * 1024)
291        assert resp['status'] == 200, 'status size 4'
292        assert resp['body'] == body, 'status body 4'
293
294        body = '0123456789abcdef' * 8 * 64 * 1024
295        resp = self.post(body=body, read_buffer_size=1024 * 1024)
296        assert resp['status'] == 200, 'status size 8'
297        assert resp['body'] == body, 'status body 8'
298
299        body = '0123456789abcdef' * 16 * 64 * 1024
300        resp = self.post(body=body, read_buffer_size=1024 * 1024)
301        assert resp['status'] == 200, 'status size 16'
302        assert resp['body'] == body, 'status body 16'
303
304        body = '0123456789abcdef' * 32 * 64 * 1024
305        resp = self.post(body=body, read_buffer_size=1024 * 1024)
306        assert resp['status'] == 200, 'status size 32'
307        assert resp['body'] == body, 'status body 32'
308
309    @pytest.mark.skip('not yet')
310    def test_settings_negative_value(self):
311        assert 'error' in self.conf(
312            {'http': {'max_body_size': -1}}, 'settings'
313        ), 'settings negative value'
314
315    def test_settings_body_buffer_size(self):
316        self.load('mirror')
317
318        assert 'success' in self.conf(
319            {
320                'http': {
321                    'max_body_size': 64 * 1024 * 1024,
322                    'body_buffer_size': 32 * 1024 * 1024,
323                }
324            },
325            'settings',
326        )
327
328        body = '0123456789abcdef'
329        resp = self.post(body=body)
330        assert bool(resp), 'response from application'
331        assert resp['status'] == 200, 'status'
332        assert resp['body'] == body, 'body'
333
334        body = '0123456789abcdef' * 1024 * 1024
335        resp = self.post(body=body, read_buffer_size=1024 * 1024)
336        assert bool(resp), 'response from application 2'
337        assert resp['status'] == 200, 'status 2'
338        assert resp['body'] == body, 'body 2'
339
340        body = '0123456789abcdef' * 2 * 1024 * 1024
341        resp = self.post(body=body, read_buffer_size=1024 * 1024)
342        assert bool(resp), 'response from application 3'
343        assert resp['status'] == 200, 'status 3'
344        assert resp['body'] == body, 'body 3'
345
346        body = '0123456789abcdef' * 3 * 1024 * 1024
347        resp = self.post(body=body, read_buffer_size=1024 * 1024)
348        assert bool(resp), 'response from application 4'
349        assert resp['status'] == 200, 'status 4'
350        assert resp['body'] == body, 'body 4'
351