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({'http': {'send_timeout': 1}}, 'settings') 211 212 data = req(addr, data_len) 213 assert re.search(r'200 OK', data), 'send timeout status' 214 assert len(data) < data_len, 'send timeout data ' 215 216 self.conf({'http': {'send_timeout': 7}}, 'settings') 217 218 data = req(addr, data_len) 219 assert re.search(r'200 OK', data), 'send timeout status 2' 220 assert len(data) > data_len, 'send timeout data 2' 221 222 def test_settings_idle_timeout(self): 223 self.load('empty') 224 225 def req(): 226 (resp, sock) = self.get( 227 headers={'Host': 'localhost', 'Connection': 'keep-alive'}, 228 start=True, 229 read_timeout=1, 230 ) 231 232 time.sleep(3) 233 234 return self.get(sock=sock) 235 236 assert self.get()['status'] == 200, 'init' 237 238 assert 'success' in self.conf({'http': {'idle_timeout': 2}}, 'settings') 239 assert req()['status'] == 408, 'status idle timeout' 240 241 assert 'success' in self.conf({'http': {'idle_timeout': 7}}, 'settings') 242 assert req()['status'] == 200, 'status idle timeout 2' 243 244 def test_settings_idle_timeout_2(self): 245 self.load('empty') 246 247 def req(): 248 _, sock = self.http(b'', start=True, raw=True, no_recv=True) 249 250 time.sleep(3) 251 252 return self.get(sock=sock) 253 254 assert self.get()['status'] == 200, 'init' 255 256 assert 'success' in self.conf({'http': {'idle_timeout': 1}}, 'settings') 257 assert req()['status'] == 408, 'status idle timeout' 258 259 assert 'success' in self.conf({'http': {'idle_timeout': 7}}, 'settings') 260 assert req()['status'] == 200, 'status idle timeout 2' 261 262 def test_settings_max_body_size(self): 263 self.load('empty') 264 265 assert 'success' in self.conf( 266 {'http': {'max_body_size': 5}}, 'settings' 267 ) 268 269 assert self.post(body='01234')['status'] == 200, 'status size' 270 assert self.post(body='012345')['status'] == 413, 'status size max' 271 272 def test_settings_max_body_size_large(self): 273 self.load('mirror') 274 275 assert 'success' in self.conf( 276 {'http': {'max_body_size': 32 * 1024 * 1024}}, 'settings' 277 ) 278 279 body = '0123456789abcdef' * 4 * 64 * 1024 280 resp = self.post(body=body, read_buffer_size=1024 * 1024) 281 assert resp['status'] == 200, 'status size 4' 282 assert resp['body'] == body, 'status body 4' 283 284 body = '0123456789abcdef' * 8 * 64 * 1024 285 resp = self.post(body=body, read_buffer_size=1024 * 1024) 286 assert resp['status'] == 200, 'status size 8' 287 assert resp['body'] == body, 'status body 8' 288 289 body = '0123456789abcdef' * 16 * 64 * 1024 290 resp = self.post(body=body, read_buffer_size=1024 * 1024) 291 assert resp['status'] == 200, 'status size 16' 292 assert resp['body'] == body, 'status body 16' 293 294 body = '0123456789abcdef' * 32 * 64 * 1024 295 resp = self.post(body=body, read_buffer_size=1024 * 1024) 296 assert resp['status'] == 200, 'status size 32' 297 assert resp['body'] == body, 'status body 32' 298 299 @pytest.mark.skip('not yet') 300 def test_settings_negative_value(self): 301 assert 'error' in self.conf( 302 {'http': {'max_body_size': -1}}, 'settings' 303 ), 'settings negative value' 304 305 def test_settings_body_buffer_size(self): 306 self.load('mirror') 307 308 assert 'success' in self.conf( 309 { 310 'http': { 311 'max_body_size': 64 * 1024 * 1024, 312 'body_buffer_size': 32 * 1024 * 1024, 313 } 314 }, 315 'settings', 316 ) 317 318 body = '0123456789abcdef' 319 resp = self.post(body=body) 320 assert bool(resp), 'response from application' 321 assert resp['status'] == 200, 'status' 322 assert resp['body'] == body, 'body' 323 324 body = '0123456789abcdef' * 1024 * 1024 325 resp = self.post(body=body, read_buffer_size=1024 * 1024) 326 assert bool(resp), 'response from application 2' 327 assert resp['status'] == 200, 'status 2' 328 assert resp['body'] == body, 'body 2' 329 330 body = '0123456789abcdef' * 2 * 1024 * 1024 331 resp = self.post(body=body, read_buffer_size=1024 * 1024) 332 assert bool(resp), 'response from application 3' 333 assert resp['status'] == 200, 'status 3' 334 assert resp['body'] == body, 'body 3' 335 336 body = '0123456789abcdef' * 3 * 1024 * 1024 337 resp = self.post(body=body, read_buffer_size=1024 * 1024) 338 assert bool(resp), 'response from application 4' 339 assert resp['status'] == 200, 'status 4' 340 assert resp['body'] == body, 'body 4' 341