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