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