11304St.nateldemoura@f5.comimport grp 21791Szelenkov@nginx.comimport os 31304St.nateldemoura@f5.comimport pwd 41477Szelenkov@nginx.comimport re 5899Szelenkov@nginx.comimport time 61477Szelenkov@nginx.com 71635Szelenkov@nginx.comimport pytest 81019Szelenkov@nginx.comfrom unit.applications.lang.python import TestApplicationPython 91730Szelenkov@nginx.comfrom unit.option import option 10484Szelenkov@nginx.com 111017Szelenkov@nginx.com 121019Szelenkov@nginx.comclass TestPythonApplication(TestApplicationPython): 131467Szelenkov@nginx.com prerequisites = {'modules': {'python': 'all'}} 14484Szelenkov@nginx.com 151283Szelenkov@nginx.com def findall(self, pattern): 161654Szelenkov@nginx.com with open(option.temp_dir + '/unit.log', 'r', errors='ignore') as f: 171283Szelenkov@nginx.com return re.findall(pattern, f.read()) 181283Szelenkov@nginx.com 19552Szelenkov@nginx.com def test_python_application_variables(self): 20552Szelenkov@nginx.com self.load('variables') 21484Szelenkov@nginx.com 22484Szelenkov@nginx.com body = 'Test body string.' 23484Szelenkov@nginx.com 241605Smax.romanov@nginx.com resp = self.http( 251605Smax.romanov@nginx.com b"""POST / HTTP/1.1 261605Smax.romanov@nginx.comHost: localhost 271605Smax.romanov@nginx.comContent-Length: %d 281605Smax.romanov@nginx.comCustom-Header: blah 291605Smax.romanov@nginx.comCustom-hEader: Blah 301605Smax.romanov@nginx.comContent-Type: text/html 311605Smax.romanov@nginx.comConnection: close 321605Smax.romanov@nginx.comcustom-header: BLAH 331605Smax.romanov@nginx.com 341605Smax.romanov@nginx.com%s""" % (len(body), body.encode()), 351605Smax.romanov@nginx.com raw=True, 361017Szelenkov@nginx.com ) 37484Szelenkov@nginx.com 381596Szelenkov@nginx.com assert resp['status'] == 200, 'status' 39505Szelenkov@nginx.com headers = resp['headers'] 40674Szelenkov@nginx.com header_server = headers.pop('Server') 411596Szelenkov@nginx.com assert re.search(r'Unit/[\d\.]+', header_server), 'server header' 421596Szelenkov@nginx.com assert ( 431596Szelenkov@nginx.com headers.pop('Server-Software') == header_server 441596Szelenkov@nginx.com ), 'server software header' 45599Szelenkov@nginx.com 46599Szelenkov@nginx.com date = headers.pop('Date') 471596Szelenkov@nginx.com assert date[-4:] == ' GMT', 'date header timezone' 481596Szelenkov@nginx.com assert ( 491596Szelenkov@nginx.com abs(self.date_to_sec_epoch(date) - self.sec_epoch()) < 5 501596Szelenkov@nginx.com ), 'date header' 51599Szelenkov@nginx.com 521596Szelenkov@nginx.com assert headers == { 531596Szelenkov@nginx.com 'Connection': 'close', 541596Szelenkov@nginx.com 'Content-Length': str(len(body)), 551596Szelenkov@nginx.com 'Content-Type': 'text/html', 561596Szelenkov@nginx.com 'Request-Method': 'POST', 571596Szelenkov@nginx.com 'Request-Uri': '/', 581596Szelenkov@nginx.com 'Http-Host': 'localhost', 591596Szelenkov@nginx.com 'Server-Protocol': 'HTTP/1.1', 601605Smax.romanov@nginx.com 'Custom-Header': 'blah, Blah, BLAH', 611596Szelenkov@nginx.com 'Wsgi-Version': '(1, 0)', 621596Szelenkov@nginx.com 'Wsgi-Url-Scheme': 'http', 631596Szelenkov@nginx.com 'Wsgi-Multithread': 'False', 641596Szelenkov@nginx.com 'Wsgi-Multiprocess': 'True', 651596Szelenkov@nginx.com 'Wsgi-Run-Once': 'False', 661596Szelenkov@nginx.com }, 'headers' 671596Szelenkov@nginx.com assert resp['body'] == body, 'body' 68484Szelenkov@nginx.com 69497Szelenkov@nginx.com def test_python_application_query_string(self): 70552Szelenkov@nginx.com self.load('query_string') 71497Szelenkov@nginx.com 72505Szelenkov@nginx.com resp = self.get(url='/?var1=val1&var2=val2') 73497Szelenkov@nginx.com 741596Szelenkov@nginx.com assert ( 751596Szelenkov@nginx.com resp['headers']['Query-String'] == 'var1=val1&var2=val2' 761596Szelenkov@nginx.com ), 'Query-String header' 77497Szelenkov@nginx.com 781171Svbart@nginx.com def test_python_application_query_string_space(self): 791171Svbart@nginx.com self.load('query_string') 801171Svbart@nginx.com 811171Svbart@nginx.com resp = self.get(url='/ ?var1=val1&var2=val2') 821596Szelenkov@nginx.com assert ( 831596Szelenkov@nginx.com resp['headers']['Query-String'] == 'var1=val1&var2=val2' 841596Szelenkov@nginx.com ), 'Query-String space' 851171Svbart@nginx.com 861171Svbart@nginx.com resp = self.get(url='/ %20?var1=val1&var2=val2') 871596Szelenkov@nginx.com assert ( 881596Szelenkov@nginx.com resp['headers']['Query-String'] == 'var1=val1&var2=val2' 891596Szelenkov@nginx.com ), 'Query-String space 2' 901171Svbart@nginx.com 911171Svbart@nginx.com resp = self.get(url='/ %20 ?var1=val1&var2=val2') 921596Szelenkov@nginx.com assert ( 931596Szelenkov@nginx.com resp['headers']['Query-String'] == 'var1=val1&var2=val2' 941596Szelenkov@nginx.com ), 'Query-String space 3' 951171Svbart@nginx.com 961171Svbart@nginx.com resp = self.get(url='/blah %20 blah? var1= val1 & var2=val2') 971596Szelenkov@nginx.com assert ( 981596Szelenkov@nginx.com resp['headers']['Query-String'] == ' var1= val1 & var2=val2' 991596Szelenkov@nginx.com ), 'Query-String space 4' 1001171Svbart@nginx.com 101894Szelenkov@nginx.com def test_python_application_query_string_empty(self): 102894Szelenkov@nginx.com self.load('query_string') 103894Szelenkov@nginx.com 104894Szelenkov@nginx.com resp = self.get(url='/?') 105894Szelenkov@nginx.com 1061596Szelenkov@nginx.com assert resp['status'] == 200, 'query string empty status' 1071596Szelenkov@nginx.com assert resp['headers']['Query-String'] == '', 'query string empty' 108894Szelenkov@nginx.com 109894Szelenkov@nginx.com def test_python_application_query_string_absent(self): 110894Szelenkov@nginx.com self.load('query_string') 111894Szelenkov@nginx.com 112894Szelenkov@nginx.com resp = self.get() 113894Szelenkov@nginx.com 1141596Szelenkov@nginx.com assert resp['status'] == 200, 'query string absent status' 1151596Szelenkov@nginx.com assert resp['headers']['Query-String'] == '', 'query string absent' 116894Szelenkov@nginx.com 1171596Szelenkov@nginx.com @pytest.mark.skip('not yet') 118495Szelenkov@nginx.com def test_python_application_server_port(self): 119552Szelenkov@nginx.com self.load('server_port') 120495Szelenkov@nginx.com 1211596Szelenkov@nginx.com assert ( 1221596Szelenkov@nginx.com self.get()['headers']['Server-Port'] == '7080' 1231596Szelenkov@nginx.com ), 'Server-Port header' 124484Szelenkov@nginx.com 1251596Szelenkov@nginx.com @pytest.mark.skip('not yet') 1261250Szelenkov@nginx.com def test_python_application_working_directory_invalid(self): 1271250Szelenkov@nginx.com self.load('empty') 1281250Szelenkov@nginx.com 1291596Szelenkov@nginx.com assert 'success' in self.conf( 1301596Szelenkov@nginx.com '"/blah"', 'applications/empty/working_directory' 1311596Szelenkov@nginx.com ), 'configure invalid working_directory' 1321250Szelenkov@nginx.com 1331596Szelenkov@nginx.com assert self.get()['status'] == 500, 'status' 1341250Szelenkov@nginx.com 135496Szelenkov@nginx.com def test_python_application_204_transfer_encoding(self): 136552Szelenkov@nginx.com self.load('204_no_content') 137496Szelenkov@nginx.com 1381596Szelenkov@nginx.com assert ( 1391596Szelenkov@nginx.com 'Transfer-Encoding' not in self.get()['headers'] 1401596Szelenkov@nginx.com ), '204 header transfer encoding' 141484Szelenkov@nginx.com 142602Szelenkov@nginx.com def test_python_application_ctx_iter_atexit(self): 143602Szelenkov@nginx.com self.load('ctx_iter_atexit') 144602Szelenkov@nginx.com 1451017Szelenkov@nginx.com resp = self.post( 1461017Szelenkov@nginx.com headers={ 1471017Szelenkov@nginx.com 'Host': 'localhost', 1481017Szelenkov@nginx.com 'Connection': 'close', 1491017Szelenkov@nginx.com 'Content-Type': 'text/html', 1501017Szelenkov@nginx.com }, 1511017Szelenkov@nginx.com body='0123456789', 1521017Szelenkov@nginx.com ) 153602Szelenkov@nginx.com 1541596Szelenkov@nginx.com assert resp['status'] == 200, 'ctx iter status' 1551596Szelenkov@nginx.com assert resp['body'] == '0123456789', 'ctx iter body' 156602Szelenkov@nginx.com 1571775Szelenkov@nginx.com assert 'success' in self.conf({"listeners": {}, "applications": {}}) 158602Szelenkov@nginx.com 1591596Szelenkov@nginx.com assert ( 1601596Szelenkov@nginx.com self.wait_for_record(r'RuntimeError') is not None 1611596Szelenkov@nginx.com ), 'ctx iter atexit' 162602Szelenkov@nginx.com 163603Szelenkov@nginx.com def test_python_keepalive_body(self): 164603Szelenkov@nginx.com self.load('mirror') 165603Szelenkov@nginx.com 1661596Szelenkov@nginx.com assert self.get()['status'] == 200, 'init' 1671029Szelenkov@nginx.com 1681453Szelenkov@nginx.com body = '0123456789' * 500 1691017Szelenkov@nginx.com (resp, sock) = self.post( 1701017Szelenkov@nginx.com headers={ 1711017Szelenkov@nginx.com 'Host': 'localhost', 1721017Szelenkov@nginx.com 'Connection': 'keep-alive', 1731017Szelenkov@nginx.com 'Content-Type': 'text/html', 1741017Szelenkov@nginx.com }, 1751017Szelenkov@nginx.com start=True, 1761453Szelenkov@nginx.com body=body, 1771029Szelenkov@nginx.com read_timeout=1, 1781017Szelenkov@nginx.com ) 179603Szelenkov@nginx.com 1801596Szelenkov@nginx.com assert resp['body'] == body, 'keep-alive 1' 181603Szelenkov@nginx.com 1821453Szelenkov@nginx.com body = '0123456789' 1831017Szelenkov@nginx.com resp = self.post( 1841017Szelenkov@nginx.com headers={ 1851017Szelenkov@nginx.com 'Host': 'localhost', 1861017Szelenkov@nginx.com 'Connection': 'close', 1871017Szelenkov@nginx.com 'Content-Type': 'text/html', 1881017Szelenkov@nginx.com }, 1891017Szelenkov@nginx.com sock=sock, 1901453Szelenkov@nginx.com body=body, 1911017Szelenkov@nginx.com ) 192603Szelenkov@nginx.com 1931596Szelenkov@nginx.com assert resp['body'] == body, 'keep-alive 2' 194603Szelenkov@nginx.com 195684Szelenkov@nginx.com def test_python_keepalive_reconfigure(self): 196684Szelenkov@nginx.com self.load('mirror') 197684Szelenkov@nginx.com 1981596Szelenkov@nginx.com assert self.get()['status'] == 200, 'init' 1991029Szelenkov@nginx.com 200684Szelenkov@nginx.com body = '0123456789' 201684Szelenkov@nginx.com conns = 3 202684Szelenkov@nginx.com socks = [] 203684Szelenkov@nginx.com 204684Szelenkov@nginx.com for i in range(conns): 2051017Szelenkov@nginx.com (resp, sock) = self.post( 2061017Szelenkov@nginx.com headers={ 2071017Szelenkov@nginx.com 'Host': 'localhost', 2081017Szelenkov@nginx.com 'Connection': 'keep-alive', 2091017Szelenkov@nginx.com 'Content-Type': 'text/html', 2101017Szelenkov@nginx.com }, 2111017Szelenkov@nginx.com start=True, 2121017Szelenkov@nginx.com body=body, 2131029Szelenkov@nginx.com read_timeout=1, 2141017Szelenkov@nginx.com ) 215684Szelenkov@nginx.com 2161596Szelenkov@nginx.com assert resp['body'] == body, 'keep-alive open' 2171695Smax.romanov@nginx.com 2181695Smax.romanov@nginx.com self.load('mirror', processes=i + 1) 219684Szelenkov@nginx.com 220684Szelenkov@nginx.com socks.append(sock) 221684Szelenkov@nginx.com 222684Szelenkov@nginx.com for i in range(conns): 2231017Szelenkov@nginx.com (resp, sock) = self.post( 2241017Szelenkov@nginx.com headers={ 2251017Szelenkov@nginx.com 'Host': 'localhost', 2261017Szelenkov@nginx.com 'Connection': 'keep-alive', 2271017Szelenkov@nginx.com 'Content-Type': 'text/html', 2281017Szelenkov@nginx.com }, 2291017Szelenkov@nginx.com start=True, 2301017Szelenkov@nginx.com sock=socks[i], 2311017Szelenkov@nginx.com body=body, 2321029Szelenkov@nginx.com read_timeout=1, 2331017Szelenkov@nginx.com ) 234684Szelenkov@nginx.com 2351596Szelenkov@nginx.com assert resp['body'] == body, 'keep-alive request' 2361695Smax.romanov@nginx.com 2371695Smax.romanov@nginx.com self.load('mirror', processes=i + 1) 238684Szelenkov@nginx.com 239684Szelenkov@nginx.com for i in range(conns): 2401017Szelenkov@nginx.com resp = self.post( 2411017Szelenkov@nginx.com headers={ 2421017Szelenkov@nginx.com 'Host': 'localhost', 2431017Szelenkov@nginx.com 'Connection': 'close', 2441017Szelenkov@nginx.com 'Content-Type': 'text/html', 2451017Szelenkov@nginx.com }, 2461017Szelenkov@nginx.com sock=socks[i], 2471017Szelenkov@nginx.com body=body, 2481017Szelenkov@nginx.com ) 249684Szelenkov@nginx.com 2501596Szelenkov@nginx.com assert resp['body'] == body, 'keep-alive close' 2511695Smax.romanov@nginx.com 2521695Smax.romanov@nginx.com self.load('mirror', processes=i + 1) 253684Szelenkov@nginx.com 254750Szelenkov@nginx.com def test_python_keepalive_reconfigure_2(self): 255750Szelenkov@nginx.com self.load('mirror') 256750Szelenkov@nginx.com 2571596Szelenkov@nginx.com assert self.get()['status'] == 200, 'init' 2581029Szelenkov@nginx.com 259750Szelenkov@nginx.com body = '0123456789' 260750Szelenkov@nginx.com 2611017Szelenkov@nginx.com (resp, sock) = self.post( 2621017Szelenkov@nginx.com headers={ 2631017Szelenkov@nginx.com 'Host': 'localhost', 2641017Szelenkov@nginx.com 'Connection': 'keep-alive', 2651017Szelenkov@nginx.com 'Content-Type': 'text/html', 2661017Szelenkov@nginx.com }, 2671017Szelenkov@nginx.com start=True, 2681017Szelenkov@nginx.com body=body, 2691029Szelenkov@nginx.com read_timeout=1, 2701017Szelenkov@nginx.com ) 271750Szelenkov@nginx.com 2721596Szelenkov@nginx.com assert resp['body'] == body, 'reconfigure 2 keep-alive 1' 273750Szelenkov@nginx.com 274750Szelenkov@nginx.com self.load('empty') 275750Szelenkov@nginx.com 2761596Szelenkov@nginx.com assert self.get()['status'] == 200, 'init' 2771029Szelenkov@nginx.com 2781017Szelenkov@nginx.com (resp, sock) = self.post( 2791017Szelenkov@nginx.com headers={ 2801017Szelenkov@nginx.com 'Host': 'localhost', 2811017Szelenkov@nginx.com 'Connection': 'close', 2821017Szelenkov@nginx.com 'Content-Type': 'text/html', 2831017Szelenkov@nginx.com }, 2841017Szelenkov@nginx.com start=True, 2851017Szelenkov@nginx.com sock=sock, 2861017Szelenkov@nginx.com body=body, 2871017Szelenkov@nginx.com ) 288750Szelenkov@nginx.com 2891596Szelenkov@nginx.com assert resp['status'] == 200, 'reconfigure 2 keep-alive 2' 2901596Szelenkov@nginx.com assert resp['body'] == '', 'reconfigure 2 keep-alive 2 body' 291750Szelenkov@nginx.com 2921596Szelenkov@nginx.com assert 'success' in self.conf( 2931596Szelenkov@nginx.com {"listeners": {}, "applications": {}} 2941596Szelenkov@nginx.com ), 'reconfigure 2 clear configuration' 295750Szelenkov@nginx.com 296750Szelenkov@nginx.com resp = self.get(sock=sock) 297750Szelenkov@nginx.com 2981596Szelenkov@nginx.com assert resp == {}, 'reconfigure 2 keep-alive 3' 299750Szelenkov@nginx.com 300750Szelenkov@nginx.com def test_python_keepalive_reconfigure_3(self): 301750Szelenkov@nginx.com self.load('empty') 302750Szelenkov@nginx.com 3031596Szelenkov@nginx.com assert self.get()['status'] == 200, 'init' 3041029Szelenkov@nginx.com 3051453Szelenkov@nginx.com (_, sock) = self.http( 3061017Szelenkov@nginx.com b"""GET / HTTP/1.1 3071017Szelenkov@nginx.com""", 3081017Szelenkov@nginx.com start=True, 3091017Szelenkov@nginx.com raw=True, 3101453Szelenkov@nginx.com no_recv=True, 3111017Szelenkov@nginx.com ) 312750Szelenkov@nginx.com 3131596Szelenkov@nginx.com assert self.get()['status'] == 200 3141453Szelenkov@nginx.com 3151596Szelenkov@nginx.com assert 'success' in self.conf( 3161596Szelenkov@nginx.com {"listeners": {}, "applications": {}} 3171596Szelenkov@nginx.com ), 'reconfigure 3 clear configuration' 318750Szelenkov@nginx.com 3191017Szelenkov@nginx.com resp = self.http( 3201017Szelenkov@nginx.com b"""Host: localhost 321750Szelenkov@nginx.comConnection: close 322750Szelenkov@nginx.com 3231017Szelenkov@nginx.com""", 3241017Szelenkov@nginx.com sock=sock, 3251017Szelenkov@nginx.com raw=True, 3261017Szelenkov@nginx.com ) 327750Szelenkov@nginx.com 3281596Szelenkov@nginx.com assert resp['status'] == 200, 'reconfigure 3' 329750Szelenkov@nginx.com 330603Szelenkov@nginx.com def test_python_atexit(self): 331603Szelenkov@nginx.com self.load('atexit') 332603Szelenkov@nginx.com 333603Szelenkov@nginx.com self.get() 334603Szelenkov@nginx.com 3351775Szelenkov@nginx.com assert 'success' in self.conf({"listeners": {}, "applications": {}}) 336603Szelenkov@nginx.com 3371596Szelenkov@nginx.com assert self.wait_for_record(r'At exit called\.') is not None, 'atexit' 338603Szelenkov@nginx.com 3391454Szelenkov@nginx.com def test_python_process_switch(self): 3401695Smax.romanov@nginx.com self.load('delayed', processes=2) 3411454Szelenkov@nginx.com 3421596Szelenkov@nginx.com self.get( 3431596Szelenkov@nginx.com headers={ 3441596Szelenkov@nginx.com 'Host': 'localhost', 3451596Szelenkov@nginx.com 'Content-Length': '0', 3461596Szelenkov@nginx.com 'X-Delay': '5', 3471596Szelenkov@nginx.com 'Connection': 'close', 3481596Szelenkov@nginx.com }, 3491596Szelenkov@nginx.com no_recv=True, 3501596Szelenkov@nginx.com ) 3511454Szelenkov@nginx.com 3521454Szelenkov@nginx.com headers_delay_1 = { 3531454Szelenkov@nginx.com 'Connection': 'close', 3541454Szelenkov@nginx.com 'Host': 'localhost', 3551454Szelenkov@nginx.com 'Content-Length': '0', 3561454Szelenkov@nginx.com 'X-Delay': '1', 3571454Szelenkov@nginx.com } 3581454Szelenkov@nginx.com 3591454Szelenkov@nginx.com self.get(headers=headers_delay_1, no_recv=True) 3601454Szelenkov@nginx.com 3611454Szelenkov@nginx.com time.sleep(0.5) 3621454Szelenkov@nginx.com 3631454Szelenkov@nginx.com for _ in range(10): 3641454Szelenkov@nginx.com self.get(headers=headers_delay_1, no_recv=True) 3651454Szelenkov@nginx.com 3661454Szelenkov@nginx.com self.get(headers=headers_delay_1) 3671454Szelenkov@nginx.com 3681596Szelenkov@nginx.com @pytest.mark.skip('not yet') 369603Szelenkov@nginx.com def test_python_application_start_response_exit(self): 370603Szelenkov@nginx.com self.load('start_response_exit') 371603Szelenkov@nginx.com 3721596Szelenkov@nginx.com assert self.get()['status'] == 500, 'start response exit' 373603Szelenkov@nginx.com 374603Szelenkov@nginx.com def test_python_application_input_iter(self): 375603Szelenkov@nginx.com self.load('input_iter') 376603Szelenkov@nginx.com 3771400Smax.romanov@nginx.com body = '''0123456789 3781400Smax.romanov@nginx.comnext line 3791400Smax.romanov@nginx.com 3801400Smax.romanov@nginx.comlast line''' 3811400Smax.romanov@nginx.com 3821400Smax.romanov@nginx.com resp = self.post(body=body) 3831596Szelenkov@nginx.com assert resp['body'] == body, 'input iter' 3841596Szelenkov@nginx.com assert resp['headers']['X-Lines-Count'] == '4', 'input iter lines' 3851400Smax.romanov@nginx.com 3861400Smax.romanov@nginx.com def test_python_application_input_readline(self): 3871400Smax.romanov@nginx.com self.load('input_readline') 3881400Smax.romanov@nginx.com 3891400Smax.romanov@nginx.com body = '''0123456789 3901400Smax.romanov@nginx.comnext line 3911400Smax.romanov@nginx.com 3921400Smax.romanov@nginx.comlast line''' 3931400Smax.romanov@nginx.com 3941400Smax.romanov@nginx.com resp = self.post(body=body) 3951596Szelenkov@nginx.com assert resp['body'] == body, 'input readline' 3961596Szelenkov@nginx.com assert resp['headers']['X-Lines-Count'] == '4', 'input readline lines' 3971400Smax.romanov@nginx.com 3981400Smax.romanov@nginx.com def test_python_application_input_readline_size(self): 3991400Smax.romanov@nginx.com self.load('input_readline_size') 4001400Smax.romanov@nginx.com 4011400Smax.romanov@nginx.com body = '''0123456789 4021400Smax.romanov@nginx.comnext line 4031400Smax.romanov@nginx.com 4041400Smax.romanov@nginx.comlast line''' 405603Szelenkov@nginx.com 4061596Szelenkov@nginx.com assert self.post(body=body)['body'] == body, 'input readline size' 4071596Szelenkov@nginx.com assert ( 4081596Szelenkov@nginx.com self.post(body='0123')['body'] == '0123' 4091596Szelenkov@nginx.com ), 'input readline size less' 4101400Smax.romanov@nginx.com 4111400Smax.romanov@nginx.com def test_python_application_input_readlines(self): 4121400Smax.romanov@nginx.com self.load('input_readlines') 4131400Smax.romanov@nginx.com 4141400Smax.romanov@nginx.com body = '''0123456789 4151400Smax.romanov@nginx.comnext line 4161400Smax.romanov@nginx.com 4171400Smax.romanov@nginx.comlast line''' 4181400Smax.romanov@nginx.com 4191400Smax.romanov@nginx.com resp = self.post(body=body) 4201596Szelenkov@nginx.com assert resp['body'] == body, 'input readlines' 4211596Szelenkov@nginx.com assert resp['headers']['X-Lines-Count'] == '4', 'input readlines lines' 4221400Smax.romanov@nginx.com 4231400Smax.romanov@nginx.com def test_python_application_input_readlines_huge(self): 4241400Smax.romanov@nginx.com self.load('input_readlines') 4251400Smax.romanov@nginx.com 4261400Smax.romanov@nginx.com body = ( 4271400Smax.romanov@nginx.com '''0123456789 abcdefghi 4281400Smax.romanov@nginx.comnext line: 0123456789 abcdefghi 4291400Smax.romanov@nginx.com 4301400Smax.romanov@nginx.comlast line: 987654321 4311400Smax.romanov@nginx.com''' 4321400Smax.romanov@nginx.com * 512 4331400Smax.romanov@nginx.com ) 4341400Smax.romanov@nginx.com 4351596Szelenkov@nginx.com assert ( 4361596Szelenkov@nginx.com self.post(body=body, read_buffer_size=16384)['body'] == body 4371596Szelenkov@nginx.com ), 'input readlines huge' 438603Szelenkov@nginx.com 439603Szelenkov@nginx.com def test_python_application_input_read_length(self): 440603Szelenkov@nginx.com self.load('input_read_length') 441603Szelenkov@nginx.com 442603Szelenkov@nginx.com body = '0123456789' 443603Szelenkov@nginx.com 4441017Szelenkov@nginx.com resp = self.post( 4451017Szelenkov@nginx.com headers={ 4461017Szelenkov@nginx.com 'Host': 'localhost', 4471017Szelenkov@nginx.com 'Input-Length': '5', 4481017Szelenkov@nginx.com 'Connection': 'close', 4491017Szelenkov@nginx.com }, 4501017Szelenkov@nginx.com body=body, 4511017Szelenkov@nginx.com ) 452603Szelenkov@nginx.com 4531596Szelenkov@nginx.com assert resp['body'] == body[:5], 'input read length lt body' 454603Szelenkov@nginx.com 4551017Szelenkov@nginx.com resp = self.post( 4561017Szelenkov@nginx.com headers={ 4571017Szelenkov@nginx.com 'Host': 'localhost', 4581017Szelenkov@nginx.com 'Input-Length': '15', 4591017Szelenkov@nginx.com 'Connection': 'close', 4601017Szelenkov@nginx.com }, 4611017Szelenkov@nginx.com body=body, 4621017Szelenkov@nginx.com ) 463603Szelenkov@nginx.com 4641596Szelenkov@nginx.com assert resp['body'] == body, 'input read length gt body' 465603Szelenkov@nginx.com 4661017Szelenkov@nginx.com resp = self.post( 4671017Szelenkov@nginx.com headers={ 4681017Szelenkov@nginx.com 'Host': 'localhost', 4691017Szelenkov@nginx.com 'Input-Length': '0', 4701017Szelenkov@nginx.com 'Connection': 'close', 4711017Szelenkov@nginx.com }, 4721017Szelenkov@nginx.com body=body, 4731017Szelenkov@nginx.com ) 474603Szelenkov@nginx.com 4751596Szelenkov@nginx.com assert resp['body'] == '', 'input read length zero' 476603Szelenkov@nginx.com 4771017Szelenkov@nginx.com resp = self.post( 4781017Szelenkov@nginx.com headers={ 4791017Szelenkov@nginx.com 'Host': 'localhost', 4801017Szelenkov@nginx.com 'Input-Length': '-1', 4811017Szelenkov@nginx.com 'Connection': 'close', 4821017Szelenkov@nginx.com }, 4831017Szelenkov@nginx.com body=body, 4841017Szelenkov@nginx.com ) 485603Szelenkov@nginx.com 4861596Szelenkov@nginx.com assert resp['body'] == body, 'input read length negative' 487603Szelenkov@nginx.com 4881596Szelenkov@nginx.com @pytest.mark.skip('not yet') 489603Szelenkov@nginx.com def test_python_application_errors_write(self): 490603Szelenkov@nginx.com self.load('errors_write') 491603Szelenkov@nginx.com 492603Szelenkov@nginx.com self.get() 493603Szelenkov@nginx.com 4941596Szelenkov@nginx.com assert ( 4951596Szelenkov@nginx.com self.wait_for_record(r'\[error\].+Error in application\.') 4961596Szelenkov@nginx.com is not None 4971596Szelenkov@nginx.com ), 'errors write' 498603Szelenkov@nginx.com 499603Szelenkov@nginx.com def test_python_application_body_array(self): 500603Szelenkov@nginx.com self.load('body_array') 501603Szelenkov@nginx.com 5021596Szelenkov@nginx.com assert self.get()['body'] == '0123456789', 'body array' 503603Szelenkov@nginx.com 504603Szelenkov@nginx.com def test_python_application_body_io(self): 505603Szelenkov@nginx.com self.load('body_io') 506603Szelenkov@nginx.com 5071596Szelenkov@nginx.com assert self.get()['body'] == '0123456789', 'body io' 508603Szelenkov@nginx.com 509603Szelenkov@nginx.com def test_python_application_body_io_file(self): 510603Szelenkov@nginx.com self.load('body_io_file') 511603Szelenkov@nginx.com 5121596Szelenkov@nginx.com assert self.get()['body'] == 'body\n', 'body io file' 513603Szelenkov@nginx.com 5141596Szelenkov@nginx.com @pytest.mark.skip('not yet') 5151736Szelenkov@nginx.com def test_python_application_syntax_error(self, skip_alert): 5161596Szelenkov@nginx.com skip_alert(r'Python failed to import module "wsgi"') 517603Szelenkov@nginx.com self.load('syntax_error') 518603Szelenkov@nginx.com 5191596Szelenkov@nginx.com assert self.get()['status'] == 500, 'syntax error' 520603Szelenkov@nginx.com 5211736Szelenkov@nginx.com def test_python_application_loading_error(self, skip_alert): 5221596Szelenkov@nginx.com skip_alert(r'Python failed to import module "blah"') 5231568Szelenkov@nginx.com 5241695Smax.romanov@nginx.com self.load('empty', module="blah") 5251568Szelenkov@nginx.com 5261596Szelenkov@nginx.com assert self.get()['status'] == 503, 'loading error' 5271568Szelenkov@nginx.com 528603Szelenkov@nginx.com def test_python_application_close(self): 529603Szelenkov@nginx.com self.load('close') 530603Szelenkov@nginx.com 531603Szelenkov@nginx.com self.get() 532603Szelenkov@nginx.com 5331596Szelenkov@nginx.com assert self.wait_for_record(r'Close called\.') is not None, 'close' 534603Szelenkov@nginx.com 535603Szelenkov@nginx.com def test_python_application_close_error(self): 536603Szelenkov@nginx.com self.load('close_error') 537603Szelenkov@nginx.com 538603Szelenkov@nginx.com self.get() 539603Szelenkov@nginx.com 5401596Szelenkov@nginx.com assert ( 5411596Szelenkov@nginx.com self.wait_for_record(r'Close called\.') is not None 5421596Szelenkov@nginx.com ), 'close error' 543603Szelenkov@nginx.com 544617Szelenkov@nginx.com def test_python_application_not_iterable(self): 545617Szelenkov@nginx.com self.load('not_iterable') 546617Szelenkov@nginx.com 547665Szelenkov@nginx.com self.get() 548617Szelenkov@nginx.com 5491596Szelenkov@nginx.com assert ( 5501028Szelenkov@nginx.com self.wait_for_record( 5511017Szelenkov@nginx.com r'\[error\].+the application returned not an iterable object' 5521596Szelenkov@nginx.com ) 5531596Szelenkov@nginx.com is not None 5541596Szelenkov@nginx.com ), 'not iterable' 555617Szelenkov@nginx.com 556664Szelenkov@nginx.com def test_python_application_write(self): 557664Szelenkov@nginx.com self.load('write') 558664Szelenkov@nginx.com 5591596Szelenkov@nginx.com assert self.get()['body'] == '0123456789', 'write' 560664Szelenkov@nginx.com 5611261Szelenkov@nginx.com def test_python_application_threading(self): 5621261Szelenkov@nginx.com """wait_for_record() timeouts after 5s while every thread works at 5631261Szelenkov@nginx.com least 3s. So without releasing GIL test should fail. 5641261Szelenkov@nginx.com """ 5651261Szelenkov@nginx.com 5661261Szelenkov@nginx.com self.load('threading') 5671261Szelenkov@nginx.com 5681261Szelenkov@nginx.com for _ in range(10): 5691261Szelenkov@nginx.com self.get(no_recv=True) 5701261Szelenkov@nginx.com 5711596Szelenkov@nginx.com assert ( 572*1804Szelenkov@nginx.com self.wait_for_record(r'\(5\) Thread: 100', wait=50) is not None 5731596Szelenkov@nginx.com ), 'last thread finished' 5741017Szelenkov@nginx.com 5751283Szelenkov@nginx.com def test_python_application_iter_exception(self): 5761283Szelenkov@nginx.com self.load('iter_exception') 5771283Szelenkov@nginx.com 5781283Szelenkov@nginx.com # Default request doesn't lead to the exception. 5791283Szelenkov@nginx.com 5801283Szelenkov@nginx.com resp = self.get( 5811283Szelenkov@nginx.com headers={ 5821283Szelenkov@nginx.com 'Host': 'localhost', 5831283Szelenkov@nginx.com 'X-Skip': '9', 5841283Szelenkov@nginx.com 'X-Chunked': '1', 5851283Szelenkov@nginx.com 'Connection': 'close', 5861283Szelenkov@nginx.com } 5871283Szelenkov@nginx.com ) 5881596Szelenkov@nginx.com assert resp['status'] == 200, 'status' 5891596Szelenkov@nginx.com assert resp['body'] == 'XXXXXXX', 'body' 5901283Szelenkov@nginx.com 5911283Szelenkov@nginx.com # Exception before start_response(). 5921283Szelenkov@nginx.com 5931596Szelenkov@nginx.com assert self.get()['status'] == 503, 'error' 5941283Szelenkov@nginx.com 5951596Szelenkov@nginx.com assert self.wait_for_record(r'Traceback') is not None, 'traceback' 5961596Szelenkov@nginx.com assert ( 5971596Szelenkov@nginx.com self.wait_for_record(r'raise Exception\(\'first exception\'\)') 5981596Szelenkov@nginx.com is not None 5991596Szelenkov@nginx.com ), 'first exception raise' 6001596Szelenkov@nginx.com assert len(self.findall(r'Traceback')) == 1, 'traceback count 1' 6011283Szelenkov@nginx.com 6021283Szelenkov@nginx.com # Exception after start_response(), before first write(). 6031283Szelenkov@nginx.com 6041596Szelenkov@nginx.com assert ( 6051283Szelenkov@nginx.com self.get( 6061283Szelenkov@nginx.com headers={ 6071283Szelenkov@nginx.com 'Host': 'localhost', 6081283Szelenkov@nginx.com 'X-Skip': '1', 6091283Szelenkov@nginx.com 'Connection': 'close', 6101283Szelenkov@nginx.com } 6111596Szelenkov@nginx.com )['status'] 6121596Szelenkov@nginx.com == 503 6131596Szelenkov@nginx.com ), 'error 2' 6141283Szelenkov@nginx.com 6151596Szelenkov@nginx.com assert ( 6161596Szelenkov@nginx.com self.wait_for_record(r'raise Exception\(\'second exception\'\)') 6171596Szelenkov@nginx.com is not None 6181596Szelenkov@nginx.com ), 'exception raise second' 6191596Szelenkov@nginx.com assert len(self.findall(r'Traceback')) == 2, 'traceback count 2' 6201283Szelenkov@nginx.com 6211283Szelenkov@nginx.com # Exception after first write(), before first __next__(). 6221283Szelenkov@nginx.com 6231283Szelenkov@nginx.com _, sock = self.get( 6241283Szelenkov@nginx.com headers={ 6251283Szelenkov@nginx.com 'Host': 'localhost', 6261283Szelenkov@nginx.com 'X-Skip': '2', 6271283Szelenkov@nginx.com 'Connection': 'keep-alive', 6281283Szelenkov@nginx.com }, 6291283Szelenkov@nginx.com start=True, 6301283Szelenkov@nginx.com ) 6311283Szelenkov@nginx.com 6321596Szelenkov@nginx.com assert ( 6331596Szelenkov@nginx.com self.wait_for_record(r'raise Exception\(\'third exception\'\)') 6341596Szelenkov@nginx.com is not None 6351596Szelenkov@nginx.com ), 'exception raise third' 6361596Szelenkov@nginx.com assert len(self.findall(r'Traceback')) == 3, 'traceback count 3' 6371283Szelenkov@nginx.com 6381596Szelenkov@nginx.com assert self.get(sock=sock) == {}, 'closed connection' 6391283Szelenkov@nginx.com 6401283Szelenkov@nginx.com # Exception after first write(), before first __next__(), 6411283Szelenkov@nginx.com # chunked (incomplete body). 6421283Szelenkov@nginx.com 6431283Szelenkov@nginx.com resp = self.get( 6441283Szelenkov@nginx.com headers={ 6451283Szelenkov@nginx.com 'Host': 'localhost', 6461283Szelenkov@nginx.com 'X-Skip': '2', 6471283Szelenkov@nginx.com 'X-Chunked': '1', 6481283Szelenkov@nginx.com 'Connection': 'close', 6491295St.nateldemoura@f5.com }, 6501596Szelenkov@nginx.com raw_resp=True, 6511283Szelenkov@nginx.com ) 6521295St.nateldemoura@f5.com if resp: 6531596Szelenkov@nginx.com assert resp[-5:] != '0\r\n\r\n', 'incomplete body' 6541596Szelenkov@nginx.com assert len(self.findall(r'Traceback')) == 4, 'traceback count 4' 6551283Szelenkov@nginx.com 6561283Szelenkov@nginx.com # Exception in __next__(). 6571283Szelenkov@nginx.com 6581283Szelenkov@nginx.com _, sock = self.get( 6591283Szelenkov@nginx.com headers={ 6601283Szelenkov@nginx.com 'Host': 'localhost', 6611283Szelenkov@nginx.com 'X-Skip': '3', 6621283Szelenkov@nginx.com 'Connection': 'keep-alive', 6631283Szelenkov@nginx.com }, 6641283Szelenkov@nginx.com start=True, 6651283Szelenkov@nginx.com ) 6661283Szelenkov@nginx.com 6671596Szelenkov@nginx.com assert ( 6681596Szelenkov@nginx.com self.wait_for_record(r'raise Exception\(\'next exception\'\)') 6691596Szelenkov@nginx.com is not None 6701596Szelenkov@nginx.com ), 'exception raise next' 6711596Szelenkov@nginx.com assert len(self.findall(r'Traceback')) == 5, 'traceback count 5' 6721283Szelenkov@nginx.com 6731596Szelenkov@nginx.com assert self.get(sock=sock) == {}, 'closed connection 2' 6741283Szelenkov@nginx.com 6751283Szelenkov@nginx.com # Exception in __next__(), chunked (incomplete body). 6761283Szelenkov@nginx.com 6771283Szelenkov@nginx.com resp = self.get( 6781283Szelenkov@nginx.com headers={ 6791283Szelenkov@nginx.com 'Host': 'localhost', 6801283Szelenkov@nginx.com 'X-Skip': '3', 6811283Szelenkov@nginx.com 'X-Chunked': '1', 6821283Szelenkov@nginx.com 'Connection': 'close', 6831295St.nateldemoura@f5.com }, 6841596Szelenkov@nginx.com raw_resp=True, 6851283Szelenkov@nginx.com ) 6861295St.nateldemoura@f5.com if resp: 6871596Szelenkov@nginx.com assert resp[-5:] != '0\r\n\r\n', 'incomplete body 2' 6881596Szelenkov@nginx.com assert len(self.findall(r'Traceback')) == 6, 'traceback count 6' 6891283Szelenkov@nginx.com 6901283Szelenkov@nginx.com # Exception before start_response() and in close(). 6911283Szelenkov@nginx.com 6921596Szelenkov@nginx.com assert ( 6931283Szelenkov@nginx.com self.get( 6941283Szelenkov@nginx.com headers={ 6951283Szelenkov@nginx.com 'Host': 'localhost', 6961283Szelenkov@nginx.com 'X-Not-Skip-Close': '1', 6971283Szelenkov@nginx.com 'Connection': 'close', 6981283Szelenkov@nginx.com } 6991596Szelenkov@nginx.com )['status'] 7001596Szelenkov@nginx.com == 503 7011596Szelenkov@nginx.com ), 'error' 7021283Szelenkov@nginx.com 7031596Szelenkov@nginx.com assert ( 7041596Szelenkov@nginx.com self.wait_for_record(r'raise Exception\(\'close exception\'\)') 7051596Szelenkov@nginx.com is not None 7061596Szelenkov@nginx.com ), 'exception raise close' 7071596Szelenkov@nginx.com assert len(self.findall(r'Traceback')) == 8, 'traceback count 8' 7081283Szelenkov@nginx.com 7091596Szelenkov@nginx.com def test_python_user_group(self, is_su): 7101596Szelenkov@nginx.com if not is_su: 7111596Szelenkov@nginx.com pytest.skip('requires root') 7121304St.nateldemoura@f5.com 7131304St.nateldemoura@f5.com nobody_uid = pwd.getpwnam('nobody').pw_uid 7141304St.nateldemoura@f5.com 7151304St.nateldemoura@f5.com group = 'nobody' 7161304St.nateldemoura@f5.com 7171304St.nateldemoura@f5.com try: 7181304St.nateldemoura@f5.com group_id = grp.getgrnam(group).gr_gid 7191706Smax.romanov@nginx.com except KeyError: 7201304St.nateldemoura@f5.com group = 'nogroup' 7211304St.nateldemoura@f5.com group_id = grp.getgrnam(group).gr_gid 7221304St.nateldemoura@f5.com 7231304St.nateldemoura@f5.com self.load('user_group') 7241304St.nateldemoura@f5.com 7251304St.nateldemoura@f5.com obj = self.getjson()['body'] 7261596Szelenkov@nginx.com assert obj['UID'] == nobody_uid, 'nobody uid' 7271596Szelenkov@nginx.com assert obj['GID'] == group_id, 'nobody gid' 7281304St.nateldemoura@f5.com 7291304St.nateldemoura@f5.com self.load('user_group', user='nobody') 7301304St.nateldemoura@f5.com 7311304St.nateldemoura@f5.com obj = self.getjson()['body'] 7321596Szelenkov@nginx.com assert obj['UID'] == nobody_uid, 'nobody uid user=nobody' 7331596Szelenkov@nginx.com assert obj['GID'] == group_id, 'nobody gid user=nobody' 7341304St.nateldemoura@f5.com 7351304St.nateldemoura@f5.com self.load('user_group', user='nobody', group=group) 7361304St.nateldemoura@f5.com 7371304St.nateldemoura@f5.com obj = self.getjson()['body'] 7381596Szelenkov@nginx.com assert obj['UID'] == nobody_uid, ( 7391596Szelenkov@nginx.com 'nobody uid user=nobody group=%s' % group 7401304St.nateldemoura@f5.com ) 7411304St.nateldemoura@f5.com 7421596Szelenkov@nginx.com assert obj['GID'] == group_id, ( 7431596Szelenkov@nginx.com 'nobody gid user=nobody group=%s' % group 7441304St.nateldemoura@f5.com ) 7451304St.nateldemoura@f5.com 7461304St.nateldemoura@f5.com self.load('user_group', group=group) 7471304St.nateldemoura@f5.com 7481304St.nateldemoura@f5.com obj = self.getjson()['body'] 7491596Szelenkov@nginx.com assert obj['UID'] == nobody_uid, 'nobody uid group=%s' % group 7501304St.nateldemoura@f5.com 7511596Szelenkov@nginx.com assert obj['GID'] == group_id, 'nobody gid group=%s' % group 7521304St.nateldemoura@f5.com 7531304St.nateldemoura@f5.com self.load('user_group', user='root') 7541304St.nateldemoura@f5.com 7551304St.nateldemoura@f5.com obj = self.getjson()['body'] 7561596Szelenkov@nginx.com assert obj['UID'] == 0, 'root uid user=root' 7571596Szelenkov@nginx.com assert obj['GID'] == 0, 'root gid user=root' 7581304St.nateldemoura@f5.com 7591304St.nateldemoura@f5.com group = 'root' 7601304St.nateldemoura@f5.com 7611304St.nateldemoura@f5.com try: 7621304St.nateldemoura@f5.com grp.getgrnam(group) 7631304St.nateldemoura@f5.com group = True 7641706Smax.romanov@nginx.com except KeyError: 7651304St.nateldemoura@f5.com group = False 7661304St.nateldemoura@f5.com 7671304St.nateldemoura@f5.com if group: 7681304St.nateldemoura@f5.com self.load('user_group', user='root', group='root') 7691304St.nateldemoura@f5.com 7701304St.nateldemoura@f5.com obj = self.getjson()['body'] 7711596Szelenkov@nginx.com assert obj['UID'] == 0, 'root uid user=root group=root' 7721596Szelenkov@nginx.com assert obj['GID'] == 0, 'root gid user=root group=root' 7731304St.nateldemoura@f5.com 7741304St.nateldemoura@f5.com self.load('user_group', group='root') 7751304St.nateldemoura@f5.com 7761304St.nateldemoura@f5.com obj = self.getjson()['body'] 7771596Szelenkov@nginx.com assert obj['UID'] == nobody_uid, 'root uid group=root' 7781596Szelenkov@nginx.com assert obj['GID'] == 0, 'root gid group=root' 7791604Smax.romanov@nginx.com 7801736Szelenkov@nginx.com def test_python_application_callable(self, skip_alert): 7811604Smax.romanov@nginx.com skip_alert(r'Python failed to get "blah" from module') 7821604Smax.romanov@nginx.com self.load('callable') 7831604Smax.romanov@nginx.com 7841604Smax.romanov@nginx.com assert self.get()['status'] == 204, 'default application response' 7851604Smax.romanov@nginx.com 7861695Smax.romanov@nginx.com self.load('callable', callable="app") 7871604Smax.romanov@nginx.com 7881604Smax.romanov@nginx.com assert self.get()['status'] == 200, 'callable response' 7891604Smax.romanov@nginx.com 7901695Smax.romanov@nginx.com self.load('callable', callable="blah") 7911604Smax.romanov@nginx.com 7921604Smax.romanov@nginx.com assert self.get()['status'] not in [200, 204], 'callable response inv' 7931604Smax.romanov@nginx.com 7941791Szelenkov@nginx.com def test_python_application_path(self): 7951791Szelenkov@nginx.com self.load('path') 7961791Szelenkov@nginx.com 7971791Szelenkov@nginx.com def set_path(path): 7981791Szelenkov@nginx.com assert 'success' in self.conf(path, 'applications/path/path') 7991791Szelenkov@nginx.com 8001791Szelenkov@nginx.com def get_path(): 8011791Szelenkov@nginx.com return self.get()['body'].split(os.pathsep) 8021791Szelenkov@nginx.com 8031791Szelenkov@nginx.com default_path = self.conf_get('/config/applications/path/path') 8041791Szelenkov@nginx.com assert 'success' in self.conf( 8051791Szelenkov@nginx.com {"PYTHONPATH": default_path}, 8061791Szelenkov@nginx.com '/config/applications/path/environment', 8071791Szelenkov@nginx.com ) 8081791Szelenkov@nginx.com 8091791Szelenkov@nginx.com self.conf_delete('/config/applications/path/path') 8101791Szelenkov@nginx.com sys_path = get_path() 8111791Szelenkov@nginx.com 8121791Szelenkov@nginx.com set_path('"/blah"') 8131791Szelenkov@nginx.com assert ['/blah', *sys_path] == get_path(), 'check path' 8141791Szelenkov@nginx.com 8151791Szelenkov@nginx.com set_path('"/new"') 8161791Szelenkov@nginx.com assert ['/new', *sys_path] == get_path(), 'check path update' 8171791Szelenkov@nginx.com 8181791Szelenkov@nginx.com set_path('["/blah1", "/blah2"]') 8191791Szelenkov@nginx.com assert ['/blah1', '/blah2', *sys_path] == get_path(), 'check path array' 8201791Szelenkov@nginx.com 8211791Szelenkov@nginx.com def test_python_application_path_invalid(self): 8221791Szelenkov@nginx.com self.load('path') 8231791Szelenkov@nginx.com 8241791Szelenkov@nginx.com def check_path(path): 8251791Szelenkov@nginx.com assert 'error' in self.conf(path, 'applications/path/path') 8261791Szelenkov@nginx.com 8271791Szelenkov@nginx.com check_path('{}') 8281791Szelenkov@nginx.com check_path('["/blah", []]') 8291791Szelenkov@nginx.com 8301683Smax.romanov@nginx.com def test_python_application_threads(self): 8311695Smax.romanov@nginx.com self.load('threads', threads=4) 8321683Smax.romanov@nginx.com 8331683Smax.romanov@nginx.com socks = [] 8341683Smax.romanov@nginx.com 8351683Smax.romanov@nginx.com for i in range(4): 8361683Smax.romanov@nginx.com (_, sock) = self.get( 8371683Smax.romanov@nginx.com headers={ 8381683Smax.romanov@nginx.com 'Host': 'localhost', 8391683Smax.romanov@nginx.com 'X-Delay': '2', 8401683Smax.romanov@nginx.com 'Connection': 'close', 8411683Smax.romanov@nginx.com }, 8421683Smax.romanov@nginx.com no_recv=True, 8431683Smax.romanov@nginx.com start=True, 8441683Smax.romanov@nginx.com ) 8451683Smax.romanov@nginx.com 8461683Smax.romanov@nginx.com socks.append(sock) 8471683Smax.romanov@nginx.com 8481683Smax.romanov@nginx.com threads = set() 8491683Smax.romanov@nginx.com 8501683Smax.romanov@nginx.com for sock in socks: 8511683Smax.romanov@nginx.com resp = self.recvall(sock).decode('utf-8') 8521683Smax.romanov@nginx.com 8531683Smax.romanov@nginx.com self.log_in(resp) 8541683Smax.romanov@nginx.com 8551683Smax.romanov@nginx.com resp = self._resp_to_dict(resp) 8561683Smax.romanov@nginx.com 8571683Smax.romanov@nginx.com assert resp['status'] == 200, 'status' 8581683Smax.romanov@nginx.com 8591683Smax.romanov@nginx.com threads.add(resp['headers']['X-Thread']) 8601683Smax.romanov@nginx.com 8611683Smax.romanov@nginx.com assert resp['headers']['Wsgi-Multithread'] == 'True', 'multithread' 8621683Smax.romanov@nginx.com 8631683Smax.romanov@nginx.com sock.close() 8641683Smax.romanov@nginx.com 8651683Smax.romanov@nginx.com assert len(socks) == len(threads), 'threads differs' 866