11304St.nateldemoura@f5.comimport grp 21304St.nateldemoura@f5.comimport pwd 31477Szelenkov@nginx.comimport re 4899Szelenkov@nginx.comimport time 51477Szelenkov@nginx.com 61635Szelenkov@nginx.comimport pytest 71635Szelenkov@nginx.com 81654Szelenkov@nginx.comfrom conftest import option 91635Szelenkov@nginx.comfrom conftest import skip_alert 101654Szelenkov@nginx.comfrom conftest import unit_stop 111019Szelenkov@nginx.comfrom unit.applications.lang.python import TestApplicationPython 12484Szelenkov@nginx.com 131017Szelenkov@nginx.com 141019Szelenkov@nginx.comclass TestPythonApplication(TestApplicationPython): 151467Szelenkov@nginx.com prerequisites = {'modules': {'python': 'all'}} 16484Szelenkov@nginx.com 171283Szelenkov@nginx.com def findall(self, pattern): 181654Szelenkov@nginx.com with open(option.temp_dir + '/unit.log', 'r', errors='ignore') as f: 191283Szelenkov@nginx.com return re.findall(pattern, f.read()) 201283Szelenkov@nginx.com 21552Szelenkov@nginx.com def test_python_application_variables(self): 22552Szelenkov@nginx.com self.load('variables') 23484Szelenkov@nginx.com 24484Szelenkov@nginx.com body = 'Test body string.' 25484Szelenkov@nginx.com 261605Smax.romanov@nginx.com resp = self.http( 271605Smax.romanov@nginx.com b"""POST / HTTP/1.1 281605Smax.romanov@nginx.comHost: localhost 291605Smax.romanov@nginx.comContent-Length: %d 301605Smax.romanov@nginx.comCustom-Header: blah 311605Smax.romanov@nginx.comCustom-hEader: Blah 321605Smax.romanov@nginx.comContent-Type: text/html 331605Smax.romanov@nginx.comConnection: close 341605Smax.romanov@nginx.comcustom-header: BLAH 351605Smax.romanov@nginx.com 361605Smax.romanov@nginx.com%s""" % (len(body), body.encode()), 371605Smax.romanov@nginx.com raw=True, 381017Szelenkov@nginx.com ) 39484Szelenkov@nginx.com 401596Szelenkov@nginx.com assert resp['status'] == 200, 'status' 41505Szelenkov@nginx.com headers = resp['headers'] 42674Szelenkov@nginx.com header_server = headers.pop('Server') 431596Szelenkov@nginx.com assert re.search(r'Unit/[\d\.]+', header_server), 'server header' 441596Szelenkov@nginx.com assert ( 451596Szelenkov@nginx.com headers.pop('Server-Software') == header_server 461596Szelenkov@nginx.com ), 'server software header' 47599Szelenkov@nginx.com 48599Szelenkov@nginx.com date = headers.pop('Date') 491596Szelenkov@nginx.com assert date[-4:] == ' GMT', 'date header timezone' 501596Szelenkov@nginx.com assert ( 511596Szelenkov@nginx.com abs(self.date_to_sec_epoch(date) - self.sec_epoch()) < 5 521596Szelenkov@nginx.com ), 'date header' 53599Szelenkov@nginx.com 541596Szelenkov@nginx.com assert headers == { 551596Szelenkov@nginx.com 'Connection': 'close', 561596Szelenkov@nginx.com 'Content-Length': str(len(body)), 571596Szelenkov@nginx.com 'Content-Type': 'text/html', 581596Szelenkov@nginx.com 'Request-Method': 'POST', 591596Szelenkov@nginx.com 'Request-Uri': '/', 601596Szelenkov@nginx.com 'Http-Host': 'localhost', 611596Szelenkov@nginx.com 'Server-Protocol': 'HTTP/1.1', 621605Smax.romanov@nginx.com 'Custom-Header': 'blah, Blah, BLAH', 631596Szelenkov@nginx.com 'Wsgi-Version': '(1, 0)', 641596Szelenkov@nginx.com 'Wsgi-Url-Scheme': 'http', 651596Szelenkov@nginx.com 'Wsgi-Multithread': 'False', 661596Szelenkov@nginx.com 'Wsgi-Multiprocess': 'True', 671596Szelenkov@nginx.com 'Wsgi-Run-Once': 'False', 681596Szelenkov@nginx.com }, 'headers' 691596Szelenkov@nginx.com assert resp['body'] == body, 'body' 70484Szelenkov@nginx.com 71497Szelenkov@nginx.com def test_python_application_query_string(self): 72552Szelenkov@nginx.com self.load('query_string') 73497Szelenkov@nginx.com 74505Szelenkov@nginx.com resp = self.get(url='/?var1=val1&var2=val2') 75497Szelenkov@nginx.com 761596Szelenkov@nginx.com assert ( 771596Szelenkov@nginx.com resp['headers']['Query-String'] == 'var1=val1&var2=val2' 781596Szelenkov@nginx.com ), 'Query-String header' 79497Szelenkov@nginx.com 801171Svbart@nginx.com def test_python_application_query_string_space(self): 811171Svbart@nginx.com self.load('query_string') 821171Svbart@nginx.com 831171Svbart@nginx.com resp = self.get(url='/ ?var1=val1&var2=val2') 841596Szelenkov@nginx.com assert ( 851596Szelenkov@nginx.com resp['headers']['Query-String'] == 'var1=val1&var2=val2' 861596Szelenkov@nginx.com ), 'Query-String space' 871171Svbart@nginx.com 881171Svbart@nginx.com resp = self.get(url='/ %20?var1=val1&var2=val2') 891596Szelenkov@nginx.com assert ( 901596Szelenkov@nginx.com resp['headers']['Query-String'] == 'var1=val1&var2=val2' 911596Szelenkov@nginx.com ), 'Query-String space 2' 921171Svbart@nginx.com 931171Svbart@nginx.com resp = self.get(url='/ %20 ?var1=val1&var2=val2') 941596Szelenkov@nginx.com assert ( 951596Szelenkov@nginx.com resp['headers']['Query-String'] == 'var1=val1&var2=val2' 961596Szelenkov@nginx.com ), 'Query-String space 3' 971171Svbart@nginx.com 981171Svbart@nginx.com resp = self.get(url='/blah %20 blah? var1= val1 & var2=val2') 991596Szelenkov@nginx.com assert ( 1001596Szelenkov@nginx.com resp['headers']['Query-String'] == ' var1= val1 & var2=val2' 1011596Szelenkov@nginx.com ), 'Query-String space 4' 1021171Svbart@nginx.com 103894Szelenkov@nginx.com def test_python_application_query_string_empty(self): 104894Szelenkov@nginx.com self.load('query_string') 105894Szelenkov@nginx.com 106894Szelenkov@nginx.com resp = self.get(url='/?') 107894Szelenkov@nginx.com 1081596Szelenkov@nginx.com assert resp['status'] == 200, 'query string empty status' 1091596Szelenkov@nginx.com assert resp['headers']['Query-String'] == '', 'query string empty' 110894Szelenkov@nginx.com 111894Szelenkov@nginx.com def test_python_application_query_string_absent(self): 112894Szelenkov@nginx.com self.load('query_string') 113894Szelenkov@nginx.com 114894Szelenkov@nginx.com resp = self.get() 115894Szelenkov@nginx.com 1161596Szelenkov@nginx.com assert resp['status'] == 200, 'query string absent status' 1171596Szelenkov@nginx.com assert resp['headers']['Query-String'] == '', 'query string absent' 118894Szelenkov@nginx.com 1191596Szelenkov@nginx.com @pytest.mark.skip('not yet') 120495Szelenkov@nginx.com def test_python_application_server_port(self): 121552Szelenkov@nginx.com self.load('server_port') 122495Szelenkov@nginx.com 1231596Szelenkov@nginx.com assert ( 1241596Szelenkov@nginx.com self.get()['headers']['Server-Port'] == '7080' 1251596Szelenkov@nginx.com ), 'Server-Port header' 126484Szelenkov@nginx.com 1271596Szelenkov@nginx.com @pytest.mark.skip('not yet') 1281250Szelenkov@nginx.com def test_python_application_working_directory_invalid(self): 1291250Szelenkov@nginx.com self.load('empty') 1301250Szelenkov@nginx.com 1311596Szelenkov@nginx.com assert 'success' in self.conf( 1321596Szelenkov@nginx.com '"/blah"', 'applications/empty/working_directory' 1331596Szelenkov@nginx.com ), 'configure invalid working_directory' 1341250Szelenkov@nginx.com 1351596Szelenkov@nginx.com assert self.get()['status'] == 500, 'status' 1361250Szelenkov@nginx.com 137496Szelenkov@nginx.com def test_python_application_204_transfer_encoding(self): 138552Szelenkov@nginx.com self.load('204_no_content') 139496Szelenkov@nginx.com 1401596Szelenkov@nginx.com assert ( 1411596Szelenkov@nginx.com 'Transfer-Encoding' not in self.get()['headers'] 1421596Szelenkov@nginx.com ), '204 header transfer encoding' 143484Szelenkov@nginx.com 144602Szelenkov@nginx.com def test_python_application_ctx_iter_atexit(self): 145602Szelenkov@nginx.com self.load('ctx_iter_atexit') 146602Szelenkov@nginx.com 1471017Szelenkov@nginx.com resp = self.post( 1481017Szelenkov@nginx.com headers={ 1491017Szelenkov@nginx.com 'Host': 'localhost', 1501017Szelenkov@nginx.com 'Connection': 'close', 1511017Szelenkov@nginx.com 'Content-Type': 'text/html', 1521017Szelenkov@nginx.com }, 1531017Szelenkov@nginx.com body='0123456789', 1541017Szelenkov@nginx.com ) 155602Szelenkov@nginx.com 1561596Szelenkov@nginx.com assert resp['status'] == 200, 'ctx iter status' 1571596Szelenkov@nginx.com assert resp['body'] == '0123456789', 'ctx iter body' 158602Szelenkov@nginx.com 1591017Szelenkov@nginx.com self.conf({"listeners": {}, "applications": {}}) 160602Szelenkov@nginx.com 1611654Szelenkov@nginx.com unit_stop() 162602Szelenkov@nginx.com 1631596Szelenkov@nginx.com assert ( 1641596Szelenkov@nginx.com self.wait_for_record(r'RuntimeError') is not None 1651596Szelenkov@nginx.com ), 'ctx iter atexit' 166602Szelenkov@nginx.com 167603Szelenkov@nginx.com def test_python_keepalive_body(self): 168603Szelenkov@nginx.com self.load('mirror') 169603Szelenkov@nginx.com 1701596Szelenkov@nginx.com assert self.get()['status'] == 200, 'init' 1711029Szelenkov@nginx.com 1721453Szelenkov@nginx.com body = '0123456789' * 500 1731017Szelenkov@nginx.com (resp, sock) = self.post( 1741017Szelenkov@nginx.com headers={ 1751017Szelenkov@nginx.com 'Host': 'localhost', 1761017Szelenkov@nginx.com 'Connection': 'keep-alive', 1771017Szelenkov@nginx.com 'Content-Type': 'text/html', 1781017Szelenkov@nginx.com }, 1791017Szelenkov@nginx.com start=True, 1801453Szelenkov@nginx.com body=body, 1811029Szelenkov@nginx.com read_timeout=1, 1821017Szelenkov@nginx.com ) 183603Szelenkov@nginx.com 1841596Szelenkov@nginx.com assert resp['body'] == body, 'keep-alive 1' 185603Szelenkov@nginx.com 1861453Szelenkov@nginx.com body = '0123456789' 1871017Szelenkov@nginx.com resp = self.post( 1881017Szelenkov@nginx.com headers={ 1891017Szelenkov@nginx.com 'Host': 'localhost', 1901017Szelenkov@nginx.com 'Connection': 'close', 1911017Szelenkov@nginx.com 'Content-Type': 'text/html', 1921017Szelenkov@nginx.com }, 1931017Szelenkov@nginx.com sock=sock, 1941453Szelenkov@nginx.com body=body, 1951017Szelenkov@nginx.com ) 196603Szelenkov@nginx.com 1971596Szelenkov@nginx.com assert resp['body'] == body, 'keep-alive 2' 198603Szelenkov@nginx.com 199684Szelenkov@nginx.com def test_python_keepalive_reconfigure(self): 2001596Szelenkov@nginx.com skip_alert( 2011596Szelenkov@nginx.com r'pthread_mutex.+failed', 2021596Szelenkov@nginx.com r'failed to apply', 2031596Szelenkov@nginx.com r'process \d+ exited on signal', 2041017Szelenkov@nginx.com ) 205684Szelenkov@nginx.com self.load('mirror') 206684Szelenkov@nginx.com 2071596Szelenkov@nginx.com assert self.get()['status'] == 200, 'init' 2081029Szelenkov@nginx.com 209684Szelenkov@nginx.com body = '0123456789' 210684Szelenkov@nginx.com conns = 3 211684Szelenkov@nginx.com socks = [] 212684Szelenkov@nginx.com 213684Szelenkov@nginx.com for i in range(conns): 2141017Szelenkov@nginx.com (resp, sock) = self.post( 2151017Szelenkov@nginx.com headers={ 2161017Szelenkov@nginx.com 'Host': 'localhost', 2171017Szelenkov@nginx.com 'Connection': 'keep-alive', 2181017Szelenkov@nginx.com 'Content-Type': 'text/html', 2191017Szelenkov@nginx.com }, 2201017Szelenkov@nginx.com start=True, 2211017Szelenkov@nginx.com body=body, 2221029Szelenkov@nginx.com read_timeout=1, 2231017Szelenkov@nginx.com ) 224684Szelenkov@nginx.com 2251596Szelenkov@nginx.com assert resp['body'] == body, 'keep-alive open' 2261596Szelenkov@nginx.com assert 'success' in self.conf( 2271596Szelenkov@nginx.com str(i + 1), 'applications/mirror/processes' 2281596Szelenkov@nginx.com ), 'reconfigure' 229684Szelenkov@nginx.com 230684Szelenkov@nginx.com socks.append(sock) 231684Szelenkov@nginx.com 232684Szelenkov@nginx.com for i in range(conns): 2331017Szelenkov@nginx.com (resp, sock) = self.post( 2341017Szelenkov@nginx.com headers={ 2351017Szelenkov@nginx.com 'Host': 'localhost', 2361017Szelenkov@nginx.com 'Connection': 'keep-alive', 2371017Szelenkov@nginx.com 'Content-Type': 'text/html', 2381017Szelenkov@nginx.com }, 2391017Szelenkov@nginx.com start=True, 2401017Szelenkov@nginx.com sock=socks[i], 2411017Szelenkov@nginx.com body=body, 2421029Szelenkov@nginx.com read_timeout=1, 2431017Szelenkov@nginx.com ) 244684Szelenkov@nginx.com 2451596Szelenkov@nginx.com assert resp['body'] == body, 'keep-alive request' 2461596Szelenkov@nginx.com assert 'success' in self.conf( 2471596Szelenkov@nginx.com str(i + 1), 'applications/mirror/processes' 2481596Szelenkov@nginx.com ), 'reconfigure 2' 249684Szelenkov@nginx.com 250684Szelenkov@nginx.com for i in range(conns): 2511017Szelenkov@nginx.com resp = self.post( 2521017Szelenkov@nginx.com headers={ 2531017Szelenkov@nginx.com 'Host': 'localhost', 2541017Szelenkov@nginx.com 'Connection': 'close', 2551017Szelenkov@nginx.com 'Content-Type': 'text/html', 2561017Szelenkov@nginx.com }, 2571017Szelenkov@nginx.com sock=socks[i], 2581017Szelenkov@nginx.com body=body, 2591017Szelenkov@nginx.com ) 260684Szelenkov@nginx.com 2611596Szelenkov@nginx.com assert resp['body'] == body, 'keep-alive close' 2621596Szelenkov@nginx.com assert 'success' in self.conf( 2631596Szelenkov@nginx.com str(i + 1), 'applications/mirror/processes' 2641596Szelenkov@nginx.com ), 'reconfigure 3' 265684Szelenkov@nginx.com 266750Szelenkov@nginx.com def test_python_keepalive_reconfigure_2(self): 267750Szelenkov@nginx.com self.load('mirror') 268750Szelenkov@nginx.com 2691596Szelenkov@nginx.com assert self.get()['status'] == 200, 'init' 2701029Szelenkov@nginx.com 271750Szelenkov@nginx.com body = '0123456789' 272750Szelenkov@nginx.com 2731017Szelenkov@nginx.com (resp, sock) = self.post( 2741017Szelenkov@nginx.com headers={ 2751017Szelenkov@nginx.com 'Host': 'localhost', 2761017Szelenkov@nginx.com 'Connection': 'keep-alive', 2771017Szelenkov@nginx.com 'Content-Type': 'text/html', 2781017Szelenkov@nginx.com }, 2791017Szelenkov@nginx.com start=True, 2801017Szelenkov@nginx.com body=body, 2811029Szelenkov@nginx.com read_timeout=1, 2821017Szelenkov@nginx.com ) 283750Szelenkov@nginx.com 2841596Szelenkov@nginx.com assert resp['body'] == body, 'reconfigure 2 keep-alive 1' 285750Szelenkov@nginx.com 286750Szelenkov@nginx.com self.load('empty') 287750Szelenkov@nginx.com 2881596Szelenkov@nginx.com assert self.get()['status'] == 200, 'init' 2891029Szelenkov@nginx.com 2901017Szelenkov@nginx.com (resp, sock) = self.post( 2911017Szelenkov@nginx.com headers={ 2921017Szelenkov@nginx.com 'Host': 'localhost', 2931017Szelenkov@nginx.com 'Connection': 'close', 2941017Szelenkov@nginx.com 'Content-Type': 'text/html', 2951017Szelenkov@nginx.com }, 2961017Szelenkov@nginx.com start=True, 2971017Szelenkov@nginx.com sock=sock, 2981017Szelenkov@nginx.com body=body, 2991017Szelenkov@nginx.com ) 300750Szelenkov@nginx.com 3011596Szelenkov@nginx.com assert resp['status'] == 200, 'reconfigure 2 keep-alive 2' 3021596Szelenkov@nginx.com assert resp['body'] == '', 'reconfigure 2 keep-alive 2 body' 303750Szelenkov@nginx.com 3041596Szelenkov@nginx.com assert 'success' in self.conf( 3051596Szelenkov@nginx.com {"listeners": {}, "applications": {}} 3061596Szelenkov@nginx.com ), 'reconfigure 2 clear configuration' 307750Szelenkov@nginx.com 308750Szelenkov@nginx.com resp = self.get(sock=sock) 309750Szelenkov@nginx.com 3101596Szelenkov@nginx.com assert resp == {}, 'reconfigure 2 keep-alive 3' 311750Szelenkov@nginx.com 312750Szelenkov@nginx.com def test_python_keepalive_reconfigure_3(self): 313750Szelenkov@nginx.com self.load('empty') 314750Szelenkov@nginx.com 3151596Szelenkov@nginx.com assert self.get()['status'] == 200, 'init' 3161029Szelenkov@nginx.com 3171453Szelenkov@nginx.com (_, sock) = self.http( 3181017Szelenkov@nginx.com b"""GET / HTTP/1.1 3191017Szelenkov@nginx.com""", 3201017Szelenkov@nginx.com start=True, 3211017Szelenkov@nginx.com raw=True, 3221453Szelenkov@nginx.com no_recv=True, 3231017Szelenkov@nginx.com ) 324750Szelenkov@nginx.com 3251596Szelenkov@nginx.com assert self.get()['status'] == 200 3261453Szelenkov@nginx.com 3271596Szelenkov@nginx.com assert 'success' in self.conf( 3281596Szelenkov@nginx.com {"listeners": {}, "applications": {}} 3291596Szelenkov@nginx.com ), 'reconfigure 3 clear configuration' 330750Szelenkov@nginx.com 3311017Szelenkov@nginx.com resp = self.http( 3321017Szelenkov@nginx.com b"""Host: localhost 333750Szelenkov@nginx.comConnection: close 334750Szelenkov@nginx.com 3351017Szelenkov@nginx.com""", 3361017Szelenkov@nginx.com sock=sock, 3371017Szelenkov@nginx.com raw=True, 3381017Szelenkov@nginx.com ) 339750Szelenkov@nginx.com 3401596Szelenkov@nginx.com assert resp['status'] == 200, 'reconfigure 3' 341750Szelenkov@nginx.com 342603Szelenkov@nginx.com def test_python_atexit(self): 343603Szelenkov@nginx.com self.load('atexit') 344603Szelenkov@nginx.com 345603Szelenkov@nginx.com self.get() 346603Szelenkov@nginx.com 3471017Szelenkov@nginx.com self.conf({"listeners": {}, "applications": {}}) 348603Szelenkov@nginx.com 3491654Szelenkov@nginx.com unit_stop() 350603Szelenkov@nginx.com 3511596Szelenkov@nginx.com assert self.wait_for_record(r'At exit called\.') is not None, 'atexit' 352603Szelenkov@nginx.com 3531454Szelenkov@nginx.com def test_python_process_switch(self): 3541454Szelenkov@nginx.com self.load('delayed') 3551454Szelenkov@nginx.com 3561596Szelenkov@nginx.com assert 'success' in self.conf( 3571596Szelenkov@nginx.com '2', 'applications/delayed/processes' 3581596Szelenkov@nginx.com ), 'configure 2 processes' 3591454Szelenkov@nginx.com 3601596Szelenkov@nginx.com self.get( 3611596Szelenkov@nginx.com headers={ 3621596Szelenkov@nginx.com 'Host': 'localhost', 3631596Szelenkov@nginx.com 'Content-Length': '0', 3641596Szelenkov@nginx.com 'X-Delay': '5', 3651596Szelenkov@nginx.com 'Connection': 'close', 3661596Szelenkov@nginx.com }, 3671596Szelenkov@nginx.com no_recv=True, 3681596Szelenkov@nginx.com ) 3691454Szelenkov@nginx.com 3701454Szelenkov@nginx.com headers_delay_1 = { 3711454Szelenkov@nginx.com 'Connection': 'close', 3721454Szelenkov@nginx.com 'Host': 'localhost', 3731454Szelenkov@nginx.com 'Content-Length': '0', 3741454Szelenkov@nginx.com 'X-Delay': '1', 3751454Szelenkov@nginx.com } 3761454Szelenkov@nginx.com 3771454Szelenkov@nginx.com self.get(headers=headers_delay_1, no_recv=True) 3781454Szelenkov@nginx.com 3791454Szelenkov@nginx.com time.sleep(0.5) 3801454Szelenkov@nginx.com 3811454Szelenkov@nginx.com for _ in range(10): 3821454Szelenkov@nginx.com self.get(headers=headers_delay_1, no_recv=True) 3831454Szelenkov@nginx.com 3841454Szelenkov@nginx.com self.get(headers=headers_delay_1) 3851454Szelenkov@nginx.com 3861596Szelenkov@nginx.com @pytest.mark.skip('not yet') 387603Szelenkov@nginx.com def test_python_application_start_response_exit(self): 388603Szelenkov@nginx.com self.load('start_response_exit') 389603Szelenkov@nginx.com 3901596Szelenkov@nginx.com assert self.get()['status'] == 500, 'start response exit' 391603Szelenkov@nginx.com 392603Szelenkov@nginx.com def test_python_application_input_iter(self): 393603Szelenkov@nginx.com self.load('input_iter') 394603Szelenkov@nginx.com 3951400Smax.romanov@nginx.com body = '''0123456789 3961400Smax.romanov@nginx.comnext line 3971400Smax.romanov@nginx.com 3981400Smax.romanov@nginx.comlast line''' 3991400Smax.romanov@nginx.com 4001400Smax.romanov@nginx.com resp = self.post(body=body) 4011596Szelenkov@nginx.com assert resp['body'] == body, 'input iter' 4021596Szelenkov@nginx.com assert resp['headers']['X-Lines-Count'] == '4', 'input iter lines' 4031400Smax.romanov@nginx.com 4041400Smax.romanov@nginx.com def test_python_application_input_readline(self): 4051400Smax.romanov@nginx.com self.load('input_readline') 4061400Smax.romanov@nginx.com 4071400Smax.romanov@nginx.com body = '''0123456789 4081400Smax.romanov@nginx.comnext line 4091400Smax.romanov@nginx.com 4101400Smax.romanov@nginx.comlast line''' 4111400Smax.romanov@nginx.com 4121400Smax.romanov@nginx.com resp = self.post(body=body) 4131596Szelenkov@nginx.com assert resp['body'] == body, 'input readline' 4141596Szelenkov@nginx.com assert resp['headers']['X-Lines-Count'] == '4', 'input readline lines' 4151400Smax.romanov@nginx.com 4161400Smax.romanov@nginx.com def test_python_application_input_readline_size(self): 4171400Smax.romanov@nginx.com self.load('input_readline_size') 4181400Smax.romanov@nginx.com 4191400Smax.romanov@nginx.com body = '''0123456789 4201400Smax.romanov@nginx.comnext line 4211400Smax.romanov@nginx.com 4221400Smax.romanov@nginx.comlast line''' 423603Szelenkov@nginx.com 4241596Szelenkov@nginx.com assert self.post(body=body)['body'] == body, 'input readline size' 4251596Szelenkov@nginx.com assert ( 4261596Szelenkov@nginx.com self.post(body='0123')['body'] == '0123' 4271596Szelenkov@nginx.com ), 'input readline size less' 4281400Smax.romanov@nginx.com 4291400Smax.romanov@nginx.com def test_python_application_input_readlines(self): 4301400Smax.romanov@nginx.com self.load('input_readlines') 4311400Smax.romanov@nginx.com 4321400Smax.romanov@nginx.com body = '''0123456789 4331400Smax.romanov@nginx.comnext line 4341400Smax.romanov@nginx.com 4351400Smax.romanov@nginx.comlast line''' 4361400Smax.romanov@nginx.com 4371400Smax.romanov@nginx.com resp = self.post(body=body) 4381596Szelenkov@nginx.com assert resp['body'] == body, 'input readlines' 4391596Szelenkov@nginx.com assert resp['headers']['X-Lines-Count'] == '4', 'input readlines lines' 4401400Smax.romanov@nginx.com 4411400Smax.romanov@nginx.com def test_python_application_input_readlines_huge(self): 4421400Smax.romanov@nginx.com self.load('input_readlines') 4431400Smax.romanov@nginx.com 4441400Smax.romanov@nginx.com body = ( 4451400Smax.romanov@nginx.com '''0123456789 abcdefghi 4461400Smax.romanov@nginx.comnext line: 0123456789 abcdefghi 4471400Smax.romanov@nginx.com 4481400Smax.romanov@nginx.comlast line: 987654321 4491400Smax.romanov@nginx.com''' 4501400Smax.romanov@nginx.com * 512 4511400Smax.romanov@nginx.com ) 4521400Smax.romanov@nginx.com 4531596Szelenkov@nginx.com assert ( 4541596Szelenkov@nginx.com self.post(body=body, read_buffer_size=16384)['body'] == body 4551596Szelenkov@nginx.com ), 'input readlines huge' 456603Szelenkov@nginx.com 457603Szelenkov@nginx.com def test_python_application_input_read_length(self): 458603Szelenkov@nginx.com self.load('input_read_length') 459603Szelenkov@nginx.com 460603Szelenkov@nginx.com body = '0123456789' 461603Szelenkov@nginx.com 4621017Szelenkov@nginx.com resp = self.post( 4631017Szelenkov@nginx.com headers={ 4641017Szelenkov@nginx.com 'Host': 'localhost', 4651017Szelenkov@nginx.com 'Input-Length': '5', 4661017Szelenkov@nginx.com 'Connection': 'close', 4671017Szelenkov@nginx.com }, 4681017Szelenkov@nginx.com body=body, 4691017Szelenkov@nginx.com ) 470603Szelenkov@nginx.com 4711596Szelenkov@nginx.com assert resp['body'] == body[:5], 'input read length lt body' 472603Szelenkov@nginx.com 4731017Szelenkov@nginx.com resp = self.post( 4741017Szelenkov@nginx.com headers={ 4751017Szelenkov@nginx.com 'Host': 'localhost', 4761017Szelenkov@nginx.com 'Input-Length': '15', 4771017Szelenkov@nginx.com 'Connection': 'close', 4781017Szelenkov@nginx.com }, 4791017Szelenkov@nginx.com body=body, 4801017Szelenkov@nginx.com ) 481603Szelenkov@nginx.com 4821596Szelenkov@nginx.com assert resp['body'] == body, 'input read length gt body' 483603Szelenkov@nginx.com 4841017Szelenkov@nginx.com resp = self.post( 4851017Szelenkov@nginx.com headers={ 4861017Szelenkov@nginx.com 'Host': 'localhost', 4871017Szelenkov@nginx.com 'Input-Length': '0', 4881017Szelenkov@nginx.com 'Connection': 'close', 4891017Szelenkov@nginx.com }, 4901017Szelenkov@nginx.com body=body, 4911017Szelenkov@nginx.com ) 492603Szelenkov@nginx.com 4931596Szelenkov@nginx.com assert resp['body'] == '', 'input read length zero' 494603Szelenkov@nginx.com 4951017Szelenkov@nginx.com resp = self.post( 4961017Szelenkov@nginx.com headers={ 4971017Szelenkov@nginx.com 'Host': 'localhost', 4981017Szelenkov@nginx.com 'Input-Length': '-1', 4991017Szelenkov@nginx.com 'Connection': 'close', 5001017Szelenkov@nginx.com }, 5011017Szelenkov@nginx.com body=body, 5021017Szelenkov@nginx.com ) 503603Szelenkov@nginx.com 5041596Szelenkov@nginx.com assert resp['body'] == body, 'input read length negative' 505603Szelenkov@nginx.com 5061596Szelenkov@nginx.com @pytest.mark.skip('not yet') 507603Szelenkov@nginx.com def test_python_application_errors_write(self): 508603Szelenkov@nginx.com self.load('errors_write') 509603Szelenkov@nginx.com 510603Szelenkov@nginx.com self.get() 511603Szelenkov@nginx.com 5121654Szelenkov@nginx.com unit_stop() 513603Szelenkov@nginx.com 5141596Szelenkov@nginx.com assert ( 5151596Szelenkov@nginx.com self.wait_for_record(r'\[error\].+Error in application\.') 5161596Szelenkov@nginx.com is not None 5171596Szelenkov@nginx.com ), 'errors write' 518603Szelenkov@nginx.com 519603Szelenkov@nginx.com def test_python_application_body_array(self): 520603Szelenkov@nginx.com self.load('body_array') 521603Szelenkov@nginx.com 5221596Szelenkov@nginx.com assert self.get()['body'] == '0123456789', 'body array' 523603Szelenkov@nginx.com 524603Szelenkov@nginx.com def test_python_application_body_io(self): 525603Szelenkov@nginx.com self.load('body_io') 526603Szelenkov@nginx.com 5271596Szelenkov@nginx.com assert self.get()['body'] == '0123456789', 'body io' 528603Szelenkov@nginx.com 529603Szelenkov@nginx.com def test_python_application_body_io_file(self): 530603Szelenkov@nginx.com self.load('body_io_file') 531603Szelenkov@nginx.com 5321596Szelenkov@nginx.com assert self.get()['body'] == 'body\n', 'body io file' 533603Szelenkov@nginx.com 5341596Szelenkov@nginx.com @pytest.mark.skip('not yet') 535603Szelenkov@nginx.com def test_python_application_syntax_error(self): 5361596Szelenkov@nginx.com skip_alert(r'Python failed to import module "wsgi"') 537603Szelenkov@nginx.com self.load('syntax_error') 538603Szelenkov@nginx.com 5391596Szelenkov@nginx.com assert self.get()['status'] == 500, 'syntax error' 540603Szelenkov@nginx.com 5411568Szelenkov@nginx.com def test_python_application_loading_error(self): 5421596Szelenkov@nginx.com skip_alert(r'Python failed to import module "blah"') 5431568Szelenkov@nginx.com 5441568Szelenkov@nginx.com self.load('empty') 5451568Szelenkov@nginx.com 5461596Szelenkov@nginx.com assert 'success' in self.conf('"blah"', 'applications/empty/module') 5471568Szelenkov@nginx.com 5481596Szelenkov@nginx.com assert self.get()['status'] == 503, 'loading error' 5491568Szelenkov@nginx.com 550603Szelenkov@nginx.com def test_python_application_close(self): 551603Szelenkov@nginx.com self.load('close') 552603Szelenkov@nginx.com 553603Szelenkov@nginx.com self.get() 554603Szelenkov@nginx.com 5551654Szelenkov@nginx.com unit_stop() 556603Szelenkov@nginx.com 5571596Szelenkov@nginx.com assert self.wait_for_record(r'Close called\.') is not None, 'close' 558603Szelenkov@nginx.com 559603Szelenkov@nginx.com def test_python_application_close_error(self): 560603Szelenkov@nginx.com self.load('close_error') 561603Szelenkov@nginx.com 562603Szelenkov@nginx.com self.get() 563603Szelenkov@nginx.com 5641654Szelenkov@nginx.com unit_stop() 565603Szelenkov@nginx.com 5661596Szelenkov@nginx.com assert ( 5671596Szelenkov@nginx.com self.wait_for_record(r'Close called\.') is not None 5681596Szelenkov@nginx.com ), 'close error' 569603Szelenkov@nginx.com 570617Szelenkov@nginx.com def test_python_application_not_iterable(self): 571617Szelenkov@nginx.com self.load('not_iterable') 572617Szelenkov@nginx.com 573665Szelenkov@nginx.com self.get() 574617Szelenkov@nginx.com 5751654Szelenkov@nginx.com unit_stop() 576617Szelenkov@nginx.com 5771596Szelenkov@nginx.com assert ( 5781028Szelenkov@nginx.com self.wait_for_record( 5791017Szelenkov@nginx.com r'\[error\].+the application returned not an iterable object' 5801596Szelenkov@nginx.com ) 5811596Szelenkov@nginx.com is not None 5821596Szelenkov@nginx.com ), 'not iterable' 583617Szelenkov@nginx.com 584664Szelenkov@nginx.com def test_python_application_write(self): 585664Szelenkov@nginx.com self.load('write') 586664Szelenkov@nginx.com 5871596Szelenkov@nginx.com assert self.get()['body'] == '0123456789', 'write' 588664Szelenkov@nginx.com 5891261Szelenkov@nginx.com def test_python_application_threading(self): 5901261Szelenkov@nginx.com """wait_for_record() timeouts after 5s while every thread works at 5911261Szelenkov@nginx.com least 3s. So without releasing GIL test should fail. 5921261Szelenkov@nginx.com """ 5931261Szelenkov@nginx.com 5941261Szelenkov@nginx.com self.load('threading') 5951261Szelenkov@nginx.com 5961261Szelenkov@nginx.com for _ in range(10): 5971261Szelenkov@nginx.com self.get(no_recv=True) 5981261Szelenkov@nginx.com 5991596Szelenkov@nginx.com assert ( 6001596Szelenkov@nginx.com self.wait_for_record(r'\(5\) Thread: 100') is not None 6011596Szelenkov@nginx.com ), 'last thread finished' 6021017Szelenkov@nginx.com 6031283Szelenkov@nginx.com def test_python_application_iter_exception(self): 6041283Szelenkov@nginx.com self.load('iter_exception') 6051283Szelenkov@nginx.com 6061283Szelenkov@nginx.com # Default request doesn't lead to the exception. 6071283Szelenkov@nginx.com 6081283Szelenkov@nginx.com resp = self.get( 6091283Szelenkov@nginx.com headers={ 6101283Szelenkov@nginx.com 'Host': 'localhost', 6111283Szelenkov@nginx.com 'X-Skip': '9', 6121283Szelenkov@nginx.com 'X-Chunked': '1', 6131283Szelenkov@nginx.com 'Connection': 'close', 6141283Szelenkov@nginx.com } 6151283Szelenkov@nginx.com ) 6161596Szelenkov@nginx.com assert resp['status'] == 200, 'status' 6171596Szelenkov@nginx.com assert resp['body'] == 'XXXXXXX', 'body' 6181283Szelenkov@nginx.com 6191283Szelenkov@nginx.com # Exception before start_response(). 6201283Szelenkov@nginx.com 6211596Szelenkov@nginx.com assert self.get()['status'] == 503, 'error' 6221283Szelenkov@nginx.com 6231596Szelenkov@nginx.com assert self.wait_for_record(r'Traceback') is not None, 'traceback' 6241596Szelenkov@nginx.com assert ( 6251596Szelenkov@nginx.com self.wait_for_record(r'raise Exception\(\'first exception\'\)') 6261596Szelenkov@nginx.com is not None 6271596Szelenkov@nginx.com ), 'first exception raise' 6281596Szelenkov@nginx.com assert len(self.findall(r'Traceback')) == 1, 'traceback count 1' 6291283Szelenkov@nginx.com 6301283Szelenkov@nginx.com # Exception after start_response(), before first write(). 6311283Szelenkov@nginx.com 6321596Szelenkov@nginx.com assert ( 6331283Szelenkov@nginx.com self.get( 6341283Szelenkov@nginx.com headers={ 6351283Szelenkov@nginx.com 'Host': 'localhost', 6361283Szelenkov@nginx.com 'X-Skip': '1', 6371283Szelenkov@nginx.com 'Connection': 'close', 6381283Szelenkov@nginx.com } 6391596Szelenkov@nginx.com )['status'] 6401596Szelenkov@nginx.com == 503 6411596Szelenkov@nginx.com ), 'error 2' 6421283Szelenkov@nginx.com 6431596Szelenkov@nginx.com assert ( 6441596Szelenkov@nginx.com self.wait_for_record(r'raise Exception\(\'second exception\'\)') 6451596Szelenkov@nginx.com is not None 6461596Szelenkov@nginx.com ), 'exception raise second' 6471596Szelenkov@nginx.com assert len(self.findall(r'Traceback')) == 2, 'traceback count 2' 6481283Szelenkov@nginx.com 6491283Szelenkov@nginx.com # Exception after first write(), before first __next__(). 6501283Szelenkov@nginx.com 6511283Szelenkov@nginx.com _, sock = self.get( 6521283Szelenkov@nginx.com headers={ 6531283Szelenkov@nginx.com 'Host': 'localhost', 6541283Szelenkov@nginx.com 'X-Skip': '2', 6551283Szelenkov@nginx.com 'Connection': 'keep-alive', 6561283Szelenkov@nginx.com }, 6571283Szelenkov@nginx.com start=True, 6581283Szelenkov@nginx.com ) 6591283Szelenkov@nginx.com 6601596Szelenkov@nginx.com assert ( 6611596Szelenkov@nginx.com self.wait_for_record(r'raise Exception\(\'third exception\'\)') 6621596Szelenkov@nginx.com is not None 6631596Szelenkov@nginx.com ), 'exception raise third' 6641596Szelenkov@nginx.com assert len(self.findall(r'Traceback')) == 3, 'traceback count 3' 6651283Szelenkov@nginx.com 6661596Szelenkov@nginx.com assert self.get(sock=sock) == {}, 'closed connection' 6671283Szelenkov@nginx.com 6681283Szelenkov@nginx.com # Exception after first write(), before first __next__(), 6691283Szelenkov@nginx.com # chunked (incomplete body). 6701283Szelenkov@nginx.com 6711283Szelenkov@nginx.com resp = self.get( 6721283Szelenkov@nginx.com headers={ 6731283Szelenkov@nginx.com 'Host': 'localhost', 6741283Szelenkov@nginx.com 'X-Skip': '2', 6751283Szelenkov@nginx.com 'X-Chunked': '1', 6761283Szelenkov@nginx.com 'Connection': 'close', 6771295St.nateldemoura@f5.com }, 6781596Szelenkov@nginx.com raw_resp=True, 6791283Szelenkov@nginx.com ) 6801295St.nateldemoura@f5.com if resp: 6811596Szelenkov@nginx.com assert resp[-5:] != '0\r\n\r\n', 'incomplete body' 6821596Szelenkov@nginx.com assert len(self.findall(r'Traceback')) == 4, 'traceback count 4' 6831283Szelenkov@nginx.com 6841283Szelenkov@nginx.com # Exception in __next__(). 6851283Szelenkov@nginx.com 6861283Szelenkov@nginx.com _, sock = self.get( 6871283Szelenkov@nginx.com headers={ 6881283Szelenkov@nginx.com 'Host': 'localhost', 6891283Szelenkov@nginx.com 'X-Skip': '3', 6901283Szelenkov@nginx.com 'Connection': 'keep-alive', 6911283Szelenkov@nginx.com }, 6921283Szelenkov@nginx.com start=True, 6931283Szelenkov@nginx.com ) 6941283Szelenkov@nginx.com 6951596Szelenkov@nginx.com assert ( 6961596Szelenkov@nginx.com self.wait_for_record(r'raise Exception\(\'next exception\'\)') 6971596Szelenkov@nginx.com is not None 6981596Szelenkov@nginx.com ), 'exception raise next' 6991596Szelenkov@nginx.com assert len(self.findall(r'Traceback')) == 5, 'traceback count 5' 7001283Szelenkov@nginx.com 7011596Szelenkov@nginx.com assert self.get(sock=sock) == {}, 'closed connection 2' 7021283Szelenkov@nginx.com 7031283Szelenkov@nginx.com # Exception in __next__(), chunked (incomplete body). 7041283Szelenkov@nginx.com 7051283Szelenkov@nginx.com resp = self.get( 7061283Szelenkov@nginx.com headers={ 7071283Szelenkov@nginx.com 'Host': 'localhost', 7081283Szelenkov@nginx.com 'X-Skip': '3', 7091283Szelenkov@nginx.com 'X-Chunked': '1', 7101283Szelenkov@nginx.com 'Connection': 'close', 7111295St.nateldemoura@f5.com }, 7121596Szelenkov@nginx.com raw_resp=True, 7131283Szelenkov@nginx.com ) 7141295St.nateldemoura@f5.com if resp: 7151596Szelenkov@nginx.com assert resp[-5:] != '0\r\n\r\n', 'incomplete body 2' 7161596Szelenkov@nginx.com assert len(self.findall(r'Traceback')) == 6, 'traceback count 6' 7171283Szelenkov@nginx.com 7181283Szelenkov@nginx.com # Exception before start_response() and in close(). 7191283Szelenkov@nginx.com 7201596Szelenkov@nginx.com assert ( 7211283Szelenkov@nginx.com self.get( 7221283Szelenkov@nginx.com headers={ 7231283Szelenkov@nginx.com 'Host': 'localhost', 7241283Szelenkov@nginx.com 'X-Not-Skip-Close': '1', 7251283Szelenkov@nginx.com 'Connection': 'close', 7261283Szelenkov@nginx.com } 7271596Szelenkov@nginx.com )['status'] 7281596Szelenkov@nginx.com == 503 7291596Szelenkov@nginx.com ), 'error' 7301283Szelenkov@nginx.com 7311596Szelenkov@nginx.com assert ( 7321596Szelenkov@nginx.com self.wait_for_record(r'raise Exception\(\'close exception\'\)') 7331596Szelenkov@nginx.com is not None 7341596Szelenkov@nginx.com ), 'exception raise close' 7351596Szelenkov@nginx.com assert len(self.findall(r'Traceback')) == 8, 'traceback count 8' 7361283Szelenkov@nginx.com 7371596Szelenkov@nginx.com def test_python_user_group(self, is_su): 7381596Szelenkov@nginx.com if not is_su: 7391596Szelenkov@nginx.com pytest.skip('requires root') 7401304St.nateldemoura@f5.com 7411304St.nateldemoura@f5.com nobody_uid = pwd.getpwnam('nobody').pw_uid 7421304St.nateldemoura@f5.com 7431304St.nateldemoura@f5.com group = 'nobody' 7441304St.nateldemoura@f5.com 7451304St.nateldemoura@f5.com try: 7461304St.nateldemoura@f5.com group_id = grp.getgrnam(group).gr_gid 7471304St.nateldemoura@f5.com except: 7481304St.nateldemoura@f5.com group = 'nogroup' 7491304St.nateldemoura@f5.com group_id = grp.getgrnam(group).gr_gid 7501304St.nateldemoura@f5.com 7511304St.nateldemoura@f5.com self.load('user_group') 7521304St.nateldemoura@f5.com 7531304St.nateldemoura@f5.com obj = self.getjson()['body'] 7541596Szelenkov@nginx.com assert obj['UID'] == nobody_uid, 'nobody uid' 7551596Szelenkov@nginx.com assert obj['GID'] == group_id, 'nobody gid' 7561304St.nateldemoura@f5.com 7571304St.nateldemoura@f5.com self.load('user_group', user='nobody') 7581304St.nateldemoura@f5.com 7591304St.nateldemoura@f5.com obj = self.getjson()['body'] 7601596Szelenkov@nginx.com assert obj['UID'] == nobody_uid, 'nobody uid user=nobody' 7611596Szelenkov@nginx.com assert obj['GID'] == group_id, 'nobody gid user=nobody' 7621304St.nateldemoura@f5.com 7631304St.nateldemoura@f5.com self.load('user_group', user='nobody', group=group) 7641304St.nateldemoura@f5.com 7651304St.nateldemoura@f5.com obj = self.getjson()['body'] 7661596Szelenkov@nginx.com assert obj['UID'] == nobody_uid, ( 7671596Szelenkov@nginx.com 'nobody uid user=nobody group=%s' % group 7681304St.nateldemoura@f5.com ) 7691304St.nateldemoura@f5.com 7701596Szelenkov@nginx.com assert obj['GID'] == group_id, ( 7711596Szelenkov@nginx.com 'nobody gid user=nobody group=%s' % group 7721304St.nateldemoura@f5.com ) 7731304St.nateldemoura@f5.com 7741304St.nateldemoura@f5.com self.load('user_group', group=group) 7751304St.nateldemoura@f5.com 7761304St.nateldemoura@f5.com obj = self.getjson()['body'] 7771596Szelenkov@nginx.com assert obj['UID'] == nobody_uid, 'nobody uid group=%s' % group 7781304St.nateldemoura@f5.com 7791596Szelenkov@nginx.com assert obj['GID'] == group_id, 'nobody gid group=%s' % group 7801304St.nateldemoura@f5.com 7811304St.nateldemoura@f5.com self.load('user_group', user='root') 7821304St.nateldemoura@f5.com 7831304St.nateldemoura@f5.com obj = self.getjson()['body'] 7841596Szelenkov@nginx.com assert obj['UID'] == 0, 'root uid user=root' 7851596Szelenkov@nginx.com assert obj['GID'] == 0, 'root gid user=root' 7861304St.nateldemoura@f5.com 7871304St.nateldemoura@f5.com group = 'root' 7881304St.nateldemoura@f5.com 7891304St.nateldemoura@f5.com try: 7901304St.nateldemoura@f5.com grp.getgrnam(group) 7911304St.nateldemoura@f5.com group = True 7921304St.nateldemoura@f5.com except: 7931304St.nateldemoura@f5.com group = False 7941304St.nateldemoura@f5.com 7951304St.nateldemoura@f5.com if group: 7961304St.nateldemoura@f5.com self.load('user_group', user='root', group='root') 7971304St.nateldemoura@f5.com 7981304St.nateldemoura@f5.com obj = self.getjson()['body'] 7991596Szelenkov@nginx.com assert obj['UID'] == 0, 'root uid user=root group=root' 8001596Szelenkov@nginx.com assert obj['GID'] == 0, 'root gid user=root group=root' 8011304St.nateldemoura@f5.com 8021304St.nateldemoura@f5.com self.load('user_group', group='root') 8031304St.nateldemoura@f5.com 8041304St.nateldemoura@f5.com obj = self.getjson()['body'] 8051596Szelenkov@nginx.com assert obj['UID'] == nobody_uid, 'root uid group=root' 8061596Szelenkov@nginx.com assert obj['GID'] == 0, 'root gid group=root' 8071604Smax.romanov@nginx.com 8081604Smax.romanov@nginx.com def test_python_application_callable(self): 8091604Smax.romanov@nginx.com skip_alert(r'Python failed to get "blah" from module') 8101604Smax.romanov@nginx.com self.load('callable') 8111604Smax.romanov@nginx.com 8121604Smax.romanov@nginx.com assert self.get()['status'] == 204, 'default application response' 8131604Smax.romanov@nginx.com 8141604Smax.romanov@nginx.com assert 'success' in self.conf( 8151604Smax.romanov@nginx.com '"app"', 'applications/callable/callable' 8161604Smax.romanov@nginx.com ) 8171604Smax.romanov@nginx.com 8181604Smax.romanov@nginx.com assert self.get()['status'] == 200, 'callable response' 8191604Smax.romanov@nginx.com 8201604Smax.romanov@nginx.com assert 'success' in self.conf( 8211604Smax.romanov@nginx.com '"blah"', 'applications/callable/callable' 8221604Smax.romanov@nginx.com ) 8231604Smax.romanov@nginx.com 8241604Smax.romanov@nginx.com assert self.get()['status'] not in [200, 204], 'callable response inv' 8251604Smax.romanov@nginx.com 8261604Smax.romanov@nginx.com assert 'success' in self.conf( 8271604Smax.romanov@nginx.com '"app"', 'applications/callable/callable' 8281604Smax.romanov@nginx.com ) 8291604Smax.romanov@nginx.com 8301604Smax.romanov@nginx.com assert self.get()['status'] == 200, 'callable response 2' 8311604Smax.romanov@nginx.com 8321604Smax.romanov@nginx.com assert 'success' in self.conf_delete('applications/callable/callable') 8331604Smax.romanov@nginx.com 8341604Smax.romanov@nginx.com assert self.get()['status'] == 204, 'default response 2' 835*1683Smax.romanov@nginx.com 836*1683Smax.romanov@nginx.com def test_python_application_threads(self): 837*1683Smax.romanov@nginx.com self.load('threads') 838*1683Smax.romanov@nginx.com 839*1683Smax.romanov@nginx.com assert 'success' in self.conf( 840*1683Smax.romanov@nginx.com '4', 'applications/threads/threads' 841*1683Smax.romanov@nginx.com ), 'configure 4 threads' 842*1683Smax.romanov@nginx.com 843*1683Smax.romanov@nginx.com socks = [] 844*1683Smax.romanov@nginx.com 845*1683Smax.romanov@nginx.com for i in range(4): 846*1683Smax.romanov@nginx.com (_, sock) = self.get( 847*1683Smax.romanov@nginx.com headers={ 848*1683Smax.romanov@nginx.com 'Host': 'localhost', 849*1683Smax.romanov@nginx.com 'X-Delay': '2', 850*1683Smax.romanov@nginx.com 'Connection': 'close', 851*1683Smax.romanov@nginx.com }, 852*1683Smax.romanov@nginx.com no_recv=True, 853*1683Smax.romanov@nginx.com start=True, 854*1683Smax.romanov@nginx.com ) 855*1683Smax.romanov@nginx.com 856*1683Smax.romanov@nginx.com socks.append(sock) 857*1683Smax.romanov@nginx.com 858*1683Smax.romanov@nginx.com threads = set() 859*1683Smax.romanov@nginx.com 860*1683Smax.romanov@nginx.com for sock in socks: 861*1683Smax.romanov@nginx.com resp = self.recvall(sock).decode('utf-8') 862*1683Smax.romanov@nginx.com 863*1683Smax.romanov@nginx.com self.log_in(resp) 864*1683Smax.romanov@nginx.com 865*1683Smax.romanov@nginx.com resp = self._resp_to_dict(resp) 866*1683Smax.romanov@nginx.com 867*1683Smax.romanov@nginx.com assert resp['status'] == 200, 'status' 868*1683Smax.romanov@nginx.com 869*1683Smax.romanov@nginx.com threads.add(resp['headers']['X-Thread']) 870*1683Smax.romanov@nginx.com 871*1683Smax.romanov@nginx.com assert resp['headers']['Wsgi-Multithread'] == 'True', 'multithread' 872*1683Smax.romanov@nginx.com 873*1683Smax.romanov@nginx.com sock.close() 874*1683Smax.romanov@nginx.com 875*1683Smax.romanov@nginx.com assert len(socks) == len(threads), 'threads differs' 876