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