11304St.nateldemoura@f5.comimport grp 21791Szelenkov@nginx.comimport os 31304St.nateldemoura@f5.comimport pwd 41477Szelenkov@nginx.comimport re 52329Szelenkov@nginx.comimport subprocess 6899Szelenkov@nginx.comimport time 72329Szelenkov@nginx.comimport venv 81477Szelenkov@nginx.com 91635Szelenkov@nginx.comimport pytest 102329Szelenkov@nginx.comfrom packaging import version 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 17*2482Szelenkov@nginx.com def test_python_application_variables(self, date_to_sec_epoch, sec_epoch): 18552Szelenkov@nginx.com self.load('variables') 19484Szelenkov@nginx.com 20484Szelenkov@nginx.com body = 'Test body string.' 21484Szelenkov@nginx.com 221605Smax.romanov@nginx.com resp = self.http( 232330Szelenkov@nginx.com f"""POST / HTTP/1.1 241605Smax.romanov@nginx.comHost: localhost 252330Szelenkov@nginx.comContent-Length: {len(body)} 261605Smax.romanov@nginx.comCustom-Header: blah 271605Smax.romanov@nginx.comCustom-hEader: Blah 281605Smax.romanov@nginx.comContent-Type: text/html 291605Smax.romanov@nginx.comConnection: close 301605Smax.romanov@nginx.comcustom-header: BLAH 311605Smax.romanov@nginx.com 322330Szelenkov@nginx.com{body}""".encode(), 331605Smax.romanov@nginx.com raw=True, 341017Szelenkov@nginx.com ) 35484Szelenkov@nginx.com 361596Szelenkov@nginx.com assert resp['status'] == 200, 'status' 37505Szelenkov@nginx.com headers = resp['headers'] 38674Szelenkov@nginx.com header_server = headers.pop('Server') 391596Szelenkov@nginx.com assert re.search(r'Unit/[\d\.]+', header_server), 'server header' 401596Szelenkov@nginx.com assert ( 411596Szelenkov@nginx.com headers.pop('Server-Software') == header_server 421596Szelenkov@nginx.com ), 'server software header' 43599Szelenkov@nginx.com 44599Szelenkov@nginx.com date = headers.pop('Date') 451596Szelenkov@nginx.com assert date[-4:] == ' GMT', 'date header timezone' 46*2482Szelenkov@nginx.com assert abs(date_to_sec_epoch(date) - sec_epoch) < 5, 'date header' 47599Szelenkov@nginx.com 481596Szelenkov@nginx.com assert headers == { 491596Szelenkov@nginx.com 'Connection': 'close', 501596Szelenkov@nginx.com 'Content-Length': str(len(body)), 511596Szelenkov@nginx.com 'Content-Type': 'text/html', 521596Szelenkov@nginx.com 'Request-Method': 'POST', 531596Szelenkov@nginx.com 'Request-Uri': '/', 541596Szelenkov@nginx.com 'Http-Host': 'localhost', 551596Szelenkov@nginx.com 'Server-Protocol': 'HTTP/1.1', 561605Smax.romanov@nginx.com 'Custom-Header': 'blah, Blah, BLAH', 571596Szelenkov@nginx.com 'Wsgi-Version': '(1, 0)', 581596Szelenkov@nginx.com 'Wsgi-Url-Scheme': 'http', 591596Szelenkov@nginx.com 'Wsgi-Multithread': 'False', 601596Szelenkov@nginx.com 'Wsgi-Multiprocess': 'True', 611596Szelenkov@nginx.com 'Wsgi-Run-Once': 'False', 621596Szelenkov@nginx.com }, 'headers' 631596Szelenkov@nginx.com assert resp['body'] == body, 'body' 64484Szelenkov@nginx.com 65497Szelenkov@nginx.com def test_python_application_query_string(self): 66552Szelenkov@nginx.com self.load('query_string') 67497Szelenkov@nginx.com 68505Szelenkov@nginx.com resp = self.get(url='/?var1=val1&var2=val2') 69497Szelenkov@nginx.com 701596Szelenkov@nginx.com assert ( 711596Szelenkov@nginx.com resp['headers']['Query-String'] == 'var1=val1&var2=val2' 721596Szelenkov@nginx.com ), 'Query-String header' 73497Szelenkov@nginx.com 741171Svbart@nginx.com def test_python_application_query_string_space(self): 751171Svbart@nginx.com self.load('query_string') 761171Svbart@nginx.com 771171Svbart@nginx.com resp = self.get(url='/ ?var1=val1&var2=val2') 781596Szelenkov@nginx.com assert ( 791596Szelenkov@nginx.com resp['headers']['Query-String'] == 'var1=val1&var2=val2' 801596Szelenkov@nginx.com ), 'Query-String space' 811171Svbart@nginx.com 821171Svbart@nginx.com resp = self.get(url='/ %20?var1=val1&var2=val2') 831596Szelenkov@nginx.com assert ( 841596Szelenkov@nginx.com resp['headers']['Query-String'] == 'var1=val1&var2=val2' 851596Szelenkov@nginx.com ), 'Query-String space 2' 861171Svbart@nginx.com 871171Svbart@nginx.com resp = self.get(url='/ %20 ?var1=val1&var2=val2') 881596Szelenkov@nginx.com assert ( 891596Szelenkov@nginx.com resp['headers']['Query-String'] == 'var1=val1&var2=val2' 901596Szelenkov@nginx.com ), 'Query-String space 3' 911171Svbart@nginx.com 921171Svbart@nginx.com resp = self.get(url='/blah %20 blah? var1= val1 & var2=val2') 931596Szelenkov@nginx.com assert ( 941596Szelenkov@nginx.com resp['headers']['Query-String'] == ' var1= val1 & var2=val2' 951596Szelenkov@nginx.com ), 'Query-String space 4' 961171Svbart@nginx.com 972273Sjeff.iadarola@gmail.com def test_python_application_prefix(self): 982273Sjeff.iadarola@gmail.com self.load('prefix', prefix='/api/rest') 992273Sjeff.iadarola@gmail.com 1002273Sjeff.iadarola@gmail.com def set_prefix(prefix): 1012330Szelenkov@nginx.com self.conf(f'"{prefix}"', 'applications/prefix/prefix') 1022273Sjeff.iadarola@gmail.com 1032273Sjeff.iadarola@gmail.com def check_prefix(url, script_name, path_info): 1042273Sjeff.iadarola@gmail.com resp = self.get(url=url) 1052273Sjeff.iadarola@gmail.com assert resp['status'] == 200 1062273Sjeff.iadarola@gmail.com assert resp['headers']['Script-Name'] == script_name 1072273Sjeff.iadarola@gmail.com assert resp['headers']['Path-Info'] == path_info 1082273Sjeff.iadarola@gmail.com 1092273Sjeff.iadarola@gmail.com check_prefix('/ap', 'NULL', '/ap') 1102273Sjeff.iadarola@gmail.com check_prefix('/api', 'NULL', '/api') 1112273Sjeff.iadarola@gmail.com check_prefix('/api/', 'NULL', '/api/') 1122273Sjeff.iadarola@gmail.com check_prefix('/api/res', 'NULL', '/api/res') 1132273Sjeff.iadarola@gmail.com check_prefix('/api/restful', 'NULL', '/api/restful') 1142273Sjeff.iadarola@gmail.com check_prefix('/api/rest', '/api/rest', '') 1152273Sjeff.iadarola@gmail.com check_prefix('/api/rest/', '/api/rest', '/') 1162273Sjeff.iadarola@gmail.com check_prefix('/api/rest/get', '/api/rest', '/get') 1172273Sjeff.iadarola@gmail.com check_prefix('/api/rest/get/blah', '/api/rest', '/get/blah') 1182273Sjeff.iadarola@gmail.com 1192273Sjeff.iadarola@gmail.com set_prefix('/api/rest/') 1202273Sjeff.iadarola@gmail.com check_prefix('/api/rest', '/api/rest', '') 1212273Sjeff.iadarola@gmail.com check_prefix('/api/restful', 'NULL', '/api/restful') 1222273Sjeff.iadarola@gmail.com check_prefix('/api/rest/', '/api/rest', '/') 1232273Sjeff.iadarola@gmail.com check_prefix('/api/rest/blah', '/api/rest', '/blah') 1242273Sjeff.iadarola@gmail.com 1252273Sjeff.iadarola@gmail.com set_prefix('/app') 1262273Sjeff.iadarola@gmail.com check_prefix('/ap', 'NULL', '/ap') 1272273Sjeff.iadarola@gmail.com check_prefix('/app', '/app', '') 1282273Sjeff.iadarola@gmail.com check_prefix('/app/', '/app', '/') 1292273Sjeff.iadarola@gmail.com check_prefix('/application/', 'NULL', '/application/') 1302273Sjeff.iadarola@gmail.com 1312273Sjeff.iadarola@gmail.com set_prefix('/') 1322273Sjeff.iadarola@gmail.com check_prefix('/', 'NULL', '/') 1332273Sjeff.iadarola@gmail.com check_prefix('/app', 'NULL', '/app') 1342273Sjeff.iadarola@gmail.com 135894Szelenkov@nginx.com def test_python_application_query_string_empty(self): 136894Szelenkov@nginx.com self.load('query_string') 137894Szelenkov@nginx.com 138894Szelenkov@nginx.com resp = self.get(url='/?') 139894Szelenkov@nginx.com 1401596Szelenkov@nginx.com assert resp['status'] == 200, 'query string empty status' 1411596Szelenkov@nginx.com assert resp['headers']['Query-String'] == '', 'query string empty' 142894Szelenkov@nginx.com 143894Szelenkov@nginx.com def test_python_application_query_string_absent(self): 144894Szelenkov@nginx.com self.load('query_string') 145894Szelenkov@nginx.com 146894Szelenkov@nginx.com resp = self.get() 147894Szelenkov@nginx.com 1481596Szelenkov@nginx.com assert resp['status'] == 200, 'query string absent status' 1491596Szelenkov@nginx.com assert resp['headers']['Query-String'] == '', 'query string absent' 150894Szelenkov@nginx.com 1511596Szelenkov@nginx.com @pytest.mark.skip('not yet') 152495Szelenkov@nginx.com def test_python_application_server_port(self): 153552Szelenkov@nginx.com self.load('server_port') 154495Szelenkov@nginx.com 1551596Szelenkov@nginx.com assert ( 1561596Szelenkov@nginx.com self.get()['headers']['Server-Port'] == '7080' 1571596Szelenkov@nginx.com ), 'Server-Port header' 158484Szelenkov@nginx.com 1591596Szelenkov@nginx.com @pytest.mark.skip('not yet') 1601250Szelenkov@nginx.com def test_python_application_working_directory_invalid(self): 1611250Szelenkov@nginx.com self.load('empty') 1621250Szelenkov@nginx.com 1631596Szelenkov@nginx.com assert 'success' in self.conf( 1641596Szelenkov@nginx.com '"/blah"', 'applications/empty/working_directory' 1651596Szelenkov@nginx.com ), 'configure invalid working_directory' 1661250Szelenkov@nginx.com 1671596Szelenkov@nginx.com assert self.get()['status'] == 500, 'status' 1681250Szelenkov@nginx.com 169496Szelenkov@nginx.com def test_python_application_204_transfer_encoding(self): 170552Szelenkov@nginx.com self.load('204_no_content') 171496Szelenkov@nginx.com 1721596Szelenkov@nginx.com assert ( 1731596Szelenkov@nginx.com 'Transfer-Encoding' not in self.get()['headers'] 1741596Szelenkov@nginx.com ), '204 header transfer encoding' 175484Szelenkov@nginx.com 176*2482Szelenkov@nginx.com def test_python_application_ctx_iter_atexit(self, wait_for_record): 177602Szelenkov@nginx.com self.load('ctx_iter_atexit') 178602Szelenkov@nginx.com 1792190Szelenkov@nginx.com resp = self.post(body='0123456789') 180602Szelenkov@nginx.com 1811596Szelenkov@nginx.com assert resp['status'] == 200, 'ctx iter status' 1821596Szelenkov@nginx.com assert resp['body'] == '0123456789', 'ctx iter body' 183602Szelenkov@nginx.com 1841775Szelenkov@nginx.com assert 'success' in self.conf({"listeners": {}, "applications": {}}) 185602Szelenkov@nginx.com 186*2482Szelenkov@nginx.com assert wait_for_record(r'RuntimeError') is not None, 'ctx iter atexit' 187602Szelenkov@nginx.com 188603Szelenkov@nginx.com def test_python_keepalive_body(self): 189603Szelenkov@nginx.com self.load('mirror') 190603Szelenkov@nginx.com 1911596Szelenkov@nginx.com assert self.get()['status'] == 200, 'init' 1921029Szelenkov@nginx.com 1931453Szelenkov@nginx.com body = '0123456789' * 500 1941017Szelenkov@nginx.com (resp, sock) = self.post( 1951017Szelenkov@nginx.com headers={ 1961017Szelenkov@nginx.com 'Host': 'localhost', 1971017Szelenkov@nginx.com 'Connection': 'keep-alive', 1981017Szelenkov@nginx.com }, 1991017Szelenkov@nginx.com start=True, 2001453Szelenkov@nginx.com body=body, 2011029Szelenkov@nginx.com read_timeout=1, 2021017Szelenkov@nginx.com ) 203603Szelenkov@nginx.com 2041596Szelenkov@nginx.com assert resp['body'] == body, 'keep-alive 1' 205603Szelenkov@nginx.com 2061453Szelenkov@nginx.com body = '0123456789' 2072190Szelenkov@nginx.com resp = self.post(sock=sock, body=body) 208603Szelenkov@nginx.com 2091596Szelenkov@nginx.com assert resp['body'] == body, 'keep-alive 2' 210603Szelenkov@nginx.com 211684Szelenkov@nginx.com def test_python_keepalive_reconfigure(self): 212684Szelenkov@nginx.com self.load('mirror') 213684Szelenkov@nginx.com 2141596Szelenkov@nginx.com assert self.get()['status'] == 200, 'init' 2151029Szelenkov@nginx.com 216684Szelenkov@nginx.com body = '0123456789' 217684Szelenkov@nginx.com conns = 3 218684Szelenkov@nginx.com socks = [] 219684Szelenkov@nginx.com 220684Szelenkov@nginx.com for i in range(conns): 2211017Szelenkov@nginx.com (resp, sock) = self.post( 2221017Szelenkov@nginx.com headers={ 2231017Szelenkov@nginx.com 'Host': 'localhost', 2241017Szelenkov@nginx.com 'Connection': 'keep-alive', 2251017Szelenkov@nginx.com }, 2261017Szelenkov@nginx.com start=True, 2271017Szelenkov@nginx.com body=body, 2281029Szelenkov@nginx.com read_timeout=1, 2291017Szelenkov@nginx.com ) 230684Szelenkov@nginx.com 2311596Szelenkov@nginx.com assert resp['body'] == body, 'keep-alive open' 2321695Smax.romanov@nginx.com 2331695Smax.romanov@nginx.com self.load('mirror', processes=i + 1) 234684Szelenkov@nginx.com 235684Szelenkov@nginx.com socks.append(sock) 236684Szelenkov@nginx.com 237684Szelenkov@nginx.com for i in range(conns): 2381017Szelenkov@nginx.com (resp, sock) = self.post( 2391017Szelenkov@nginx.com headers={ 2401017Szelenkov@nginx.com 'Host': 'localhost', 2411017Szelenkov@nginx.com 'Connection': 'keep-alive', 2421017Szelenkov@nginx.com }, 2431017Szelenkov@nginx.com start=True, 2441017Szelenkov@nginx.com sock=socks[i], 2451017Szelenkov@nginx.com body=body, 2461029Szelenkov@nginx.com read_timeout=1, 2471017Szelenkov@nginx.com ) 248684Szelenkov@nginx.com 2491596Szelenkov@nginx.com assert resp['body'] == body, 'keep-alive request' 2501695Smax.romanov@nginx.com 2511695Smax.romanov@nginx.com self.load('mirror', processes=i + 1) 252684Szelenkov@nginx.com 253684Szelenkov@nginx.com for i in range(conns): 2542190Szelenkov@nginx.com resp = self.post(sock=socks[i], body=body) 255684Szelenkov@nginx.com 2561596Szelenkov@nginx.com assert resp['body'] == body, 'keep-alive close' 2571695Smax.romanov@nginx.com 2581695Smax.romanov@nginx.com self.load('mirror', processes=i + 1) 259684Szelenkov@nginx.com 260750Szelenkov@nginx.com def test_python_keepalive_reconfigure_2(self): 261750Szelenkov@nginx.com self.load('mirror') 262750Szelenkov@nginx.com 2631596Szelenkov@nginx.com assert self.get()['status'] == 200, 'init' 2641029Szelenkov@nginx.com 265750Szelenkov@nginx.com body = '0123456789' 266750Szelenkov@nginx.com 2671017Szelenkov@nginx.com (resp, sock) = self.post( 2681017Szelenkov@nginx.com headers={ 2691017Szelenkov@nginx.com 'Host': 'localhost', 2701017Szelenkov@nginx.com 'Connection': 'keep-alive', 2711017Szelenkov@nginx.com }, 2721017Szelenkov@nginx.com start=True, 2731017Szelenkov@nginx.com body=body, 2741029Szelenkov@nginx.com read_timeout=1, 2751017Szelenkov@nginx.com ) 276750Szelenkov@nginx.com 2771596Szelenkov@nginx.com assert resp['body'] == body, 'reconfigure 2 keep-alive 1' 278750Szelenkov@nginx.com 279750Szelenkov@nginx.com self.load('empty') 280750Szelenkov@nginx.com 2811596Szelenkov@nginx.com assert self.get()['status'] == 200, 'init' 2821029Szelenkov@nginx.com 2832190Szelenkov@nginx.com (resp, sock) = self.post(start=True, sock=sock, body=body) 284750Szelenkov@nginx.com 2851596Szelenkov@nginx.com assert resp['status'] == 200, 'reconfigure 2 keep-alive 2' 2861596Szelenkov@nginx.com assert resp['body'] == '', 'reconfigure 2 keep-alive 2 body' 287750Szelenkov@nginx.com 2881596Szelenkov@nginx.com assert 'success' in self.conf( 2891596Szelenkov@nginx.com {"listeners": {}, "applications": {}} 2901596Szelenkov@nginx.com ), 'reconfigure 2 clear configuration' 291750Szelenkov@nginx.com 292750Szelenkov@nginx.com resp = self.get(sock=sock) 293750Szelenkov@nginx.com 2941596Szelenkov@nginx.com assert resp == {}, 'reconfigure 2 keep-alive 3' 295750Szelenkov@nginx.com 296*2482Szelenkov@nginx.com def test_python_atexit(self, wait_for_record): 297603Szelenkov@nginx.com self.load('atexit') 298603Szelenkov@nginx.com 299603Szelenkov@nginx.com self.get() 300603Szelenkov@nginx.com 3011775Szelenkov@nginx.com assert 'success' in self.conf({"listeners": {}, "applications": {}}) 302603Szelenkov@nginx.com 303*2482Szelenkov@nginx.com assert wait_for_record(r'At exit called\.') is not None, 'atexit' 304603Szelenkov@nginx.com 3051454Szelenkov@nginx.com def test_python_process_switch(self): 3061695Smax.romanov@nginx.com self.load('delayed', processes=2) 3071454Szelenkov@nginx.com 3081596Szelenkov@nginx.com self.get( 3091596Szelenkov@nginx.com headers={ 3101596Szelenkov@nginx.com 'Host': 'localhost', 3111596Szelenkov@nginx.com 'Content-Length': '0', 3121596Szelenkov@nginx.com 'X-Delay': '5', 3131596Szelenkov@nginx.com 'Connection': 'close', 3141596Szelenkov@nginx.com }, 3151596Szelenkov@nginx.com no_recv=True, 3161596Szelenkov@nginx.com ) 3171454Szelenkov@nginx.com 3181454Szelenkov@nginx.com headers_delay_1 = { 3191454Szelenkov@nginx.com 'Connection': 'close', 3201454Szelenkov@nginx.com 'Host': 'localhost', 3211454Szelenkov@nginx.com 'Content-Length': '0', 3221454Szelenkov@nginx.com 'X-Delay': '1', 3231454Szelenkov@nginx.com } 3241454Szelenkov@nginx.com 3251454Szelenkov@nginx.com self.get(headers=headers_delay_1, no_recv=True) 3261454Szelenkov@nginx.com 3271454Szelenkov@nginx.com time.sleep(0.5) 3281454Szelenkov@nginx.com 3291454Szelenkov@nginx.com for _ in range(10): 3301454Szelenkov@nginx.com self.get(headers=headers_delay_1, no_recv=True) 3311454Szelenkov@nginx.com 3321454Szelenkov@nginx.com self.get(headers=headers_delay_1) 3331454Szelenkov@nginx.com 3341596Szelenkov@nginx.com @pytest.mark.skip('not yet') 335603Szelenkov@nginx.com def test_python_application_start_response_exit(self): 336603Szelenkov@nginx.com self.load('start_response_exit') 337603Szelenkov@nginx.com 3381596Szelenkov@nginx.com assert self.get()['status'] == 500, 'start response exit' 339603Szelenkov@nginx.com 340603Szelenkov@nginx.com def test_python_application_input_iter(self): 341603Szelenkov@nginx.com self.load('input_iter') 342603Szelenkov@nginx.com 3431400Smax.romanov@nginx.com body = '''0123456789 3441400Smax.romanov@nginx.comnext line 3451400Smax.romanov@nginx.com 3461400Smax.romanov@nginx.comlast line''' 3471400Smax.romanov@nginx.com 3481400Smax.romanov@nginx.com resp = self.post(body=body) 3491596Szelenkov@nginx.com assert resp['body'] == body, 'input iter' 3501596Szelenkov@nginx.com assert resp['headers']['X-Lines-Count'] == '4', 'input iter lines' 3511400Smax.romanov@nginx.com 3521400Smax.romanov@nginx.com def test_python_application_input_readline(self): 3531400Smax.romanov@nginx.com self.load('input_readline') 3541400Smax.romanov@nginx.com 3551400Smax.romanov@nginx.com body = '''0123456789 3561400Smax.romanov@nginx.comnext line 3571400Smax.romanov@nginx.com 3581400Smax.romanov@nginx.comlast line''' 3591400Smax.romanov@nginx.com 3601400Smax.romanov@nginx.com resp = self.post(body=body) 3611596Szelenkov@nginx.com assert resp['body'] == body, 'input readline' 3621596Szelenkov@nginx.com assert resp['headers']['X-Lines-Count'] == '4', 'input readline lines' 3631400Smax.romanov@nginx.com 3641400Smax.romanov@nginx.com def test_python_application_input_readline_size(self): 3651400Smax.romanov@nginx.com self.load('input_readline_size') 3661400Smax.romanov@nginx.com 3671400Smax.romanov@nginx.com body = '''0123456789 3681400Smax.romanov@nginx.comnext line 3691400Smax.romanov@nginx.com 3701400Smax.romanov@nginx.comlast line''' 371603Szelenkov@nginx.com 3721596Szelenkov@nginx.com assert self.post(body=body)['body'] == body, 'input readline size' 3731596Szelenkov@nginx.com assert ( 3741596Szelenkov@nginx.com self.post(body='0123')['body'] == '0123' 3751596Szelenkov@nginx.com ), 'input readline size less' 3761400Smax.romanov@nginx.com 3771400Smax.romanov@nginx.com def test_python_application_input_readlines(self): 3781400Smax.romanov@nginx.com self.load('input_readlines') 3791400Smax.romanov@nginx.com 3801400Smax.romanov@nginx.com body = '''0123456789 3811400Smax.romanov@nginx.comnext line 3821400Smax.romanov@nginx.com 3831400Smax.romanov@nginx.comlast line''' 3841400Smax.romanov@nginx.com 3851400Smax.romanov@nginx.com resp = self.post(body=body) 3861596Szelenkov@nginx.com assert resp['body'] == body, 'input readlines' 3871596Szelenkov@nginx.com assert resp['headers']['X-Lines-Count'] == '4', 'input readlines lines' 3881400Smax.romanov@nginx.com 3891400Smax.romanov@nginx.com def test_python_application_input_readlines_huge(self): 3901400Smax.romanov@nginx.com self.load('input_readlines') 3911400Smax.romanov@nginx.com 3921400Smax.romanov@nginx.com body = ( 3931400Smax.romanov@nginx.com '''0123456789 abcdefghi 3941400Smax.romanov@nginx.comnext line: 0123456789 abcdefghi 3951400Smax.romanov@nginx.com 3961400Smax.romanov@nginx.comlast line: 987654321 3971400Smax.romanov@nginx.com''' 3981400Smax.romanov@nginx.com * 512 3991400Smax.romanov@nginx.com ) 4001400Smax.romanov@nginx.com 4011596Szelenkov@nginx.com assert ( 4021596Szelenkov@nginx.com self.post(body=body, read_buffer_size=16384)['body'] == body 4031596Szelenkov@nginx.com ), 'input readlines huge' 404603Szelenkov@nginx.com 405603Szelenkov@nginx.com def test_python_application_input_read_length(self): 406603Szelenkov@nginx.com self.load('input_read_length') 407603Szelenkov@nginx.com 408603Szelenkov@nginx.com body = '0123456789' 409603Szelenkov@nginx.com 4101017Szelenkov@nginx.com resp = self.post( 4111017Szelenkov@nginx.com headers={ 4121017Szelenkov@nginx.com 'Host': 'localhost', 4131017Szelenkov@nginx.com 'Input-Length': '5', 4141017Szelenkov@nginx.com 'Connection': 'close', 4151017Szelenkov@nginx.com }, 4161017Szelenkov@nginx.com body=body, 4171017Szelenkov@nginx.com ) 418603Szelenkov@nginx.com 4191596Szelenkov@nginx.com assert resp['body'] == body[:5], 'input read length lt body' 420603Szelenkov@nginx.com 4211017Szelenkov@nginx.com resp = self.post( 4221017Szelenkov@nginx.com headers={ 4231017Szelenkov@nginx.com 'Host': 'localhost', 4241017Szelenkov@nginx.com 'Input-Length': '15', 4251017Szelenkov@nginx.com 'Connection': 'close', 4261017Szelenkov@nginx.com }, 4271017Szelenkov@nginx.com body=body, 4281017Szelenkov@nginx.com ) 429603Szelenkov@nginx.com 4301596Szelenkov@nginx.com assert resp['body'] == body, 'input read length gt body' 431603Szelenkov@nginx.com 4321017Szelenkov@nginx.com resp = self.post( 4331017Szelenkov@nginx.com headers={ 4341017Szelenkov@nginx.com 'Host': 'localhost', 4351017Szelenkov@nginx.com 'Input-Length': '0', 4361017Szelenkov@nginx.com 'Connection': 'close', 4371017Szelenkov@nginx.com }, 4381017Szelenkov@nginx.com body=body, 4391017Szelenkov@nginx.com ) 440603Szelenkov@nginx.com 4411596Szelenkov@nginx.com assert resp['body'] == '', 'input read length zero' 442603Szelenkov@nginx.com 4431017Szelenkov@nginx.com resp = self.post( 4441017Szelenkov@nginx.com headers={ 4451017Szelenkov@nginx.com 'Host': 'localhost', 4461017Szelenkov@nginx.com 'Input-Length': '-1', 4471017Szelenkov@nginx.com 'Connection': 'close', 4481017Szelenkov@nginx.com }, 4491017Szelenkov@nginx.com body=body, 4501017Szelenkov@nginx.com ) 451603Szelenkov@nginx.com 4521596Szelenkov@nginx.com assert resp['body'] == body, 'input read length negative' 453603Szelenkov@nginx.com 4541596Szelenkov@nginx.com @pytest.mark.skip('not yet') 455*2482Szelenkov@nginx.com def test_python_application_errors_write(self, wait_for_record): 456603Szelenkov@nginx.com self.load('errors_write') 457603Szelenkov@nginx.com 458603Szelenkov@nginx.com self.get() 459603Szelenkov@nginx.com 4601596Szelenkov@nginx.com assert ( 461*2482Szelenkov@nginx.com wait_for_record(r'\[error\].+Error in application\.') is not None 4621596Szelenkov@nginx.com ), 'errors write' 463603Szelenkov@nginx.com 464603Szelenkov@nginx.com def test_python_application_body_array(self): 465603Szelenkov@nginx.com self.load('body_array') 466603Szelenkov@nginx.com 4671596Szelenkov@nginx.com assert self.get()['body'] == '0123456789', 'body array' 468603Szelenkov@nginx.com 469603Szelenkov@nginx.com def test_python_application_body_io(self): 470603Szelenkov@nginx.com self.load('body_io') 471603Szelenkov@nginx.com 4721596Szelenkov@nginx.com assert self.get()['body'] == '0123456789', 'body io' 473603Szelenkov@nginx.com 474603Szelenkov@nginx.com def test_python_application_body_io_file(self): 475603Szelenkov@nginx.com self.load('body_io_file') 476603Szelenkov@nginx.com 4771596Szelenkov@nginx.com assert self.get()['body'] == 'body\n', 'body io file' 478603Szelenkov@nginx.com 4791596Szelenkov@nginx.com @pytest.mark.skip('not yet') 4801736Szelenkov@nginx.com def test_python_application_syntax_error(self, skip_alert): 4811596Szelenkov@nginx.com skip_alert(r'Python failed to import module "wsgi"') 482603Szelenkov@nginx.com self.load('syntax_error') 483603Szelenkov@nginx.com 4841596Szelenkov@nginx.com assert self.get()['status'] == 500, 'syntax error' 485603Szelenkov@nginx.com 4861736Szelenkov@nginx.com def test_python_application_loading_error(self, skip_alert): 4871596Szelenkov@nginx.com skip_alert(r'Python failed to import module "blah"') 4881568Szelenkov@nginx.com 4891695Smax.romanov@nginx.com self.load('empty', module="blah") 4901568Szelenkov@nginx.com 4911596Szelenkov@nginx.com assert self.get()['status'] == 503, 'loading error' 4921568Szelenkov@nginx.com 493*2482Szelenkov@nginx.com def test_python_application_close(self, wait_for_record): 494603Szelenkov@nginx.com self.load('close') 495603Szelenkov@nginx.com 496603Szelenkov@nginx.com self.get() 497603Szelenkov@nginx.com 498*2482Szelenkov@nginx.com assert wait_for_record(r'Close called\.') is not None, 'close' 499603Szelenkov@nginx.com 500*2482Szelenkov@nginx.com def test_python_application_close_error(self, wait_for_record): 501603Szelenkov@nginx.com self.load('close_error') 502603Szelenkov@nginx.com 503603Szelenkov@nginx.com self.get() 504603Szelenkov@nginx.com 505*2482Szelenkov@nginx.com assert wait_for_record(r'Close called\.') is not None, 'close error' 506603Szelenkov@nginx.com 507*2482Szelenkov@nginx.com def test_python_application_not_iterable(self, wait_for_record): 508617Szelenkov@nginx.com self.load('not_iterable') 509617Szelenkov@nginx.com 510665Szelenkov@nginx.com self.get() 511617Szelenkov@nginx.com 5121596Szelenkov@nginx.com assert ( 513*2482Szelenkov@nginx.com wait_for_record( 5141017Szelenkov@nginx.com r'\[error\].+the application returned not an iterable object' 5151596Szelenkov@nginx.com ) 5161596Szelenkov@nginx.com is not None 5171596Szelenkov@nginx.com ), 'not iterable' 518617Szelenkov@nginx.com 519664Szelenkov@nginx.com def test_python_application_write(self): 520664Szelenkov@nginx.com self.load('write') 521664Szelenkov@nginx.com 5221596Szelenkov@nginx.com assert self.get()['body'] == '0123456789', 'write' 523664Szelenkov@nginx.com 5242329Szelenkov@nginx.com def test_python_application_encoding(self): 5252329Szelenkov@nginx.com self.load('encoding') 5262329Szelenkov@nginx.com 5272329Szelenkov@nginx.com try: 5282329Szelenkov@nginx.com locales = ( 5292329Szelenkov@nginx.com subprocess.check_output( 5302329Szelenkov@nginx.com ['locale', '-a'], 5312329Szelenkov@nginx.com stderr=subprocess.STDOUT, 5322329Szelenkov@nginx.com ) 5332329Szelenkov@nginx.com .decode() 5342329Szelenkov@nginx.com .splitlines() 5352329Szelenkov@nginx.com ) 5362329Szelenkov@nginx.com except ( 5372329Szelenkov@nginx.com FileNotFoundError, 5382329Szelenkov@nginx.com UnicodeDecodeError, 5392329Szelenkov@nginx.com subprocess.CalledProcessError, 5402329Szelenkov@nginx.com ): 5412329Szelenkov@nginx.com pytest.skip('require locale') 5422329Szelenkov@nginx.com 5432329Szelenkov@nginx.com to_check = [ 5442329Szelenkov@nginx.com re.compile(r'.*UTF[-_]?8'), 5452329Szelenkov@nginx.com re.compile(r'.*ISO[-_]?8859[-_]?1'), 5462329Szelenkov@nginx.com ] 5472329Szelenkov@nginx.com matches = [ 5482329Szelenkov@nginx.com loc 5492329Szelenkov@nginx.com for loc in locales 5502329Szelenkov@nginx.com if any(pattern.match(loc.upper()) for pattern in to_check) 5512329Szelenkov@nginx.com ] 5522329Szelenkov@nginx.com 5532329Szelenkov@nginx.com if not matches: 5542329Szelenkov@nginx.com pytest.skip('no available locales') 5552329Szelenkov@nginx.com 5562329Szelenkov@nginx.com def unify(str): 5572329Szelenkov@nginx.com str.upper().replace('-', '').replace('_', '') 5582329Szelenkov@nginx.com 5592329Szelenkov@nginx.com for loc in matches: 5602329Szelenkov@nginx.com assert 'success' in self.conf( 5612329Szelenkov@nginx.com {"LC_CTYPE": loc, "LC_ALL": ""}, 5622329Szelenkov@nginx.com '/config/applications/encoding/environment', 5632329Szelenkov@nginx.com ) 5642329Szelenkov@nginx.com resp = self.get() 5652329Szelenkov@nginx.com assert resp['status'] == 200, 'status' 5662329Szelenkov@nginx.com assert unify(resp['headers']['X-Encoding']) == unify( 5672329Szelenkov@nginx.com loc.split('.')[-1] 5682329Szelenkov@nginx.com ) 5692329Szelenkov@nginx.com 5702329Szelenkov@nginx.com def test_python_application_unicode(self, temp_dir): 5712329Szelenkov@nginx.com try: 5722329Szelenkov@nginx.com app_type = self.get_application_type() 5732329Szelenkov@nginx.com v = version.Version(app_type.split()[-1]) 5742329Szelenkov@nginx.com if v.major != 3: 5752329Szelenkov@nginx.com raise version.InvalidVersion 5762329Szelenkov@nginx.com 5772329Szelenkov@nginx.com except version.InvalidVersion: 5782329Szelenkov@nginx.com pytest.skip('require python module version 3') 5792329Szelenkov@nginx.com 5802330Szelenkov@nginx.com venv_path = f'{temp_dir}/venv' 5812329Szelenkov@nginx.com venv.create(venv_path) 5822329Szelenkov@nginx.com 5832329Szelenkov@nginx.com self.load('unicode') 5842329Szelenkov@nginx.com assert 'success' in self.conf( 5852330Szelenkov@nginx.com f'"{venv_path}"', 5862329Szelenkov@nginx.com '/config/applications/unicode/home', 5872329Szelenkov@nginx.com ) 5882329Szelenkov@nginx.com assert ( 5892329Szelenkov@nginx.com self.get( 5902329Szelenkov@nginx.com headers={ 5912329Szelenkov@nginx.com 'Host': 'localhost', 5922329Szelenkov@nginx.com 'Temp-dir': temp_dir, 5932329Szelenkov@nginx.com 'Connection': 'close', 5942329Szelenkov@nginx.com } 5952329Szelenkov@nginx.com )['status'] 5962329Szelenkov@nginx.com == 200 5972329Szelenkov@nginx.com ) 5982329Szelenkov@nginx.com 599*2482Szelenkov@nginx.com def test_python_application_threading(self, wait_for_record): 6001261Szelenkov@nginx.com """wait_for_record() timeouts after 5s while every thread works at 6011261Szelenkov@nginx.com least 3s. So without releasing GIL test should fail. 6021261Szelenkov@nginx.com """ 6031261Szelenkov@nginx.com 6041261Szelenkov@nginx.com self.load('threading') 6051261Szelenkov@nginx.com 6061261Szelenkov@nginx.com for _ in range(10): 6071261Szelenkov@nginx.com self.get(no_recv=True) 6081261Szelenkov@nginx.com 6091596Szelenkov@nginx.com assert ( 610*2482Szelenkov@nginx.com wait_for_record(r'\(5\) Thread: 100', wait=50) is not None 6111596Szelenkov@nginx.com ), 'last thread finished' 6121017Szelenkov@nginx.com 613*2482Szelenkov@nginx.com def test_python_application_iter_exception(self, findall, wait_for_record): 6141283Szelenkov@nginx.com self.load('iter_exception') 6151283Szelenkov@nginx.com 6161283Szelenkov@nginx.com # Default request doesn't lead to the exception. 6171283Szelenkov@nginx.com 6181283Szelenkov@nginx.com resp = self.get( 6191283Szelenkov@nginx.com headers={ 6201283Szelenkov@nginx.com 'Host': 'localhost', 6211283Szelenkov@nginx.com 'X-Skip': '9', 6221283Szelenkov@nginx.com 'X-Chunked': '1', 6231283Szelenkov@nginx.com 'Connection': 'close', 6241283Szelenkov@nginx.com } 6251283Szelenkov@nginx.com ) 6261596Szelenkov@nginx.com assert resp['status'] == 200, 'status' 6271596Szelenkov@nginx.com assert resp['body'] == 'XXXXXXX', 'body' 6281283Szelenkov@nginx.com 6291283Szelenkov@nginx.com # Exception before start_response(). 6301283Szelenkov@nginx.com 6311596Szelenkov@nginx.com assert self.get()['status'] == 503, 'error' 6321283Szelenkov@nginx.com 633*2482Szelenkov@nginx.com assert wait_for_record(r'Traceback') is not None, 'traceback' 6341596Szelenkov@nginx.com assert ( 635*2482Szelenkov@nginx.com wait_for_record(r"raise Exception\('first exception'\)") is not None 6361596Szelenkov@nginx.com ), 'first exception raise' 637*2482Szelenkov@nginx.com assert len(findall(r'Traceback')) == 1, 'traceback count 1' 6381283Szelenkov@nginx.com 6391283Szelenkov@nginx.com # Exception after start_response(), before first write(). 6401283Szelenkov@nginx.com 6411596Szelenkov@nginx.com assert ( 6421283Szelenkov@nginx.com self.get( 6431283Szelenkov@nginx.com headers={ 6441283Szelenkov@nginx.com 'Host': 'localhost', 6451283Szelenkov@nginx.com 'X-Skip': '1', 6461283Szelenkov@nginx.com 'Connection': 'close', 6471283Szelenkov@nginx.com } 6481596Szelenkov@nginx.com )['status'] 6491596Szelenkov@nginx.com == 503 6501596Szelenkov@nginx.com ), 'error 2' 6511283Szelenkov@nginx.com 6521596Szelenkov@nginx.com assert ( 653*2482Szelenkov@nginx.com wait_for_record(r"raise Exception\('second exception'\)") 6541596Szelenkov@nginx.com is not None 6551596Szelenkov@nginx.com ), 'exception raise second' 656*2482Szelenkov@nginx.com assert len(findall(r'Traceback')) == 2, 'traceback count 2' 6571283Szelenkov@nginx.com 6581283Szelenkov@nginx.com # Exception after first write(), before first __next__(). 6591283Szelenkov@nginx.com 6601283Szelenkov@nginx.com _, sock = self.get( 6611283Szelenkov@nginx.com headers={ 6621283Szelenkov@nginx.com 'Host': 'localhost', 6631283Szelenkov@nginx.com 'X-Skip': '2', 6641283Szelenkov@nginx.com 'Connection': 'keep-alive', 6651283Szelenkov@nginx.com }, 6661283Szelenkov@nginx.com start=True, 6671283Szelenkov@nginx.com ) 6681283Szelenkov@nginx.com 6691596Szelenkov@nginx.com assert ( 670*2482Szelenkov@nginx.com wait_for_record(r"raise Exception\('third exception'\)") is not None 6711596Szelenkov@nginx.com ), 'exception raise third' 672*2482Szelenkov@nginx.com assert len(findall(r'Traceback')) == 3, 'traceback count 3' 6731283Szelenkov@nginx.com 6741596Szelenkov@nginx.com assert self.get(sock=sock) == {}, 'closed connection' 6751283Szelenkov@nginx.com 6761283Szelenkov@nginx.com # Exception after first write(), before first __next__(), 6771283Szelenkov@nginx.com # chunked (incomplete body). 6781283Szelenkov@nginx.com 6791283Szelenkov@nginx.com resp = self.get( 6801283Szelenkov@nginx.com headers={ 6811283Szelenkov@nginx.com 'Host': 'localhost', 6821283Szelenkov@nginx.com 'X-Skip': '2', 6831283Szelenkov@nginx.com 'X-Chunked': '1', 6841283Szelenkov@nginx.com 'Connection': 'close', 6851295St.nateldemoura@f5.com }, 6861596Szelenkov@nginx.com raw_resp=True, 6871283Szelenkov@nginx.com ) 6881295St.nateldemoura@f5.com if resp: 6891596Szelenkov@nginx.com assert resp[-5:] != '0\r\n\r\n', 'incomplete body' 690*2482Szelenkov@nginx.com assert len(findall(r'Traceback')) == 4, 'traceback count 4' 6911283Szelenkov@nginx.com 6921283Szelenkov@nginx.com # Exception in __next__(). 6931283Szelenkov@nginx.com 6941283Szelenkov@nginx.com _, sock = self.get( 6951283Szelenkov@nginx.com headers={ 6961283Szelenkov@nginx.com 'Host': 'localhost', 6971283Szelenkov@nginx.com 'X-Skip': '3', 6981283Szelenkov@nginx.com 'Connection': 'keep-alive', 6991283Szelenkov@nginx.com }, 7001283Szelenkov@nginx.com start=True, 7011283Szelenkov@nginx.com ) 7021283Szelenkov@nginx.com 7031596Szelenkov@nginx.com assert ( 704*2482Szelenkov@nginx.com wait_for_record(r"raise Exception\('next exception'\)") is not None 7051596Szelenkov@nginx.com ), 'exception raise next' 706*2482Szelenkov@nginx.com assert len(findall(r'Traceback')) == 5, 'traceback count 5' 7071283Szelenkov@nginx.com 7081596Szelenkov@nginx.com assert self.get(sock=sock) == {}, 'closed connection 2' 7091283Szelenkov@nginx.com 7101283Szelenkov@nginx.com # Exception in __next__(), chunked (incomplete body). 7111283Szelenkov@nginx.com 7121283Szelenkov@nginx.com resp = self.get( 7131283Szelenkov@nginx.com headers={ 7141283Szelenkov@nginx.com 'Host': 'localhost', 7151283Szelenkov@nginx.com 'X-Skip': '3', 7161283Szelenkov@nginx.com 'X-Chunked': '1', 7171283Szelenkov@nginx.com 'Connection': 'close', 7181295St.nateldemoura@f5.com }, 7191596Szelenkov@nginx.com raw_resp=True, 7201283Szelenkov@nginx.com ) 7211295St.nateldemoura@f5.com if resp: 7221596Szelenkov@nginx.com assert resp[-5:] != '0\r\n\r\n', 'incomplete body 2' 723*2482Szelenkov@nginx.com assert len(findall(r'Traceback')) == 6, 'traceback count 6' 7241283Szelenkov@nginx.com 7251283Szelenkov@nginx.com # Exception before start_response() and in close(). 7261283Szelenkov@nginx.com 7271596Szelenkov@nginx.com assert ( 7281283Szelenkov@nginx.com self.get( 7291283Szelenkov@nginx.com headers={ 7301283Szelenkov@nginx.com 'Host': 'localhost', 7311283Szelenkov@nginx.com 'X-Not-Skip-Close': '1', 7321283Szelenkov@nginx.com 'Connection': 'close', 7331283Szelenkov@nginx.com } 7341596Szelenkov@nginx.com )['status'] 7351596Szelenkov@nginx.com == 503 7361596Szelenkov@nginx.com ), 'error' 7371283Szelenkov@nginx.com 7381596Szelenkov@nginx.com assert ( 739*2482Szelenkov@nginx.com wait_for_record(r"raise Exception\('close exception'\)") is not None 7401596Szelenkov@nginx.com ), 'exception raise close' 741*2482Szelenkov@nginx.com assert len(findall(r'Traceback')) == 8, 'traceback count 8' 7421283Szelenkov@nginx.com 7431596Szelenkov@nginx.com def test_python_user_group(self, is_su): 7441596Szelenkov@nginx.com if not is_su: 7451596Szelenkov@nginx.com pytest.skip('requires root') 7461304St.nateldemoura@f5.com 7471304St.nateldemoura@f5.com nobody_uid = pwd.getpwnam('nobody').pw_uid 7481304St.nateldemoura@f5.com 7491304St.nateldemoura@f5.com group = 'nobody' 7501304St.nateldemoura@f5.com 7511304St.nateldemoura@f5.com try: 7521304St.nateldemoura@f5.com group_id = grp.getgrnam(group).gr_gid 7531706Smax.romanov@nginx.com except KeyError: 7541304St.nateldemoura@f5.com group = 'nogroup' 7551304St.nateldemoura@f5.com group_id = grp.getgrnam(group).gr_gid 7561304St.nateldemoura@f5.com 7571304St.nateldemoura@f5.com self.load('user_group') 7581304St.nateldemoura@f5.com 7591304St.nateldemoura@f5.com obj = self.getjson()['body'] 7601596Szelenkov@nginx.com assert obj['UID'] == nobody_uid, 'nobody uid' 7611596Szelenkov@nginx.com assert obj['GID'] == group_id, 'nobody gid' 7621304St.nateldemoura@f5.com 7631304St.nateldemoura@f5.com self.load('user_group', user='nobody') 7641304St.nateldemoura@f5.com 7651304St.nateldemoura@f5.com obj = self.getjson()['body'] 7661596Szelenkov@nginx.com assert obj['UID'] == nobody_uid, 'nobody uid user=nobody' 7671596Szelenkov@nginx.com assert obj['GID'] == group_id, 'nobody gid user=nobody' 7681304St.nateldemoura@f5.com 7691304St.nateldemoura@f5.com self.load('user_group', user='nobody', group=group) 7701304St.nateldemoura@f5.com 7711304St.nateldemoura@f5.com obj = self.getjson()['body'] 7722330Szelenkov@nginx.com assert obj['UID'] == nobody_uid, f'nobody uid user=nobody group={group}' 7732330Szelenkov@nginx.com assert obj['GID'] == group_id, f'nobody gid user=nobody group={group}' 7741304St.nateldemoura@f5.com 7751304St.nateldemoura@f5.com self.load('user_group', group=group) 7761304St.nateldemoura@f5.com 7771304St.nateldemoura@f5.com obj = self.getjson()['body'] 7782330Szelenkov@nginx.com assert obj['UID'] == nobody_uid, f'nobody uid group={group}' 7792330Szelenkov@nginx.com assert obj['GID'] == group_id, f'nobody gid group={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 7921706Smax.romanov@nginx.com except KeyError: 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 8081736Szelenkov@nginx.com def test_python_application_callable(self, skip_alert): 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 8141695Smax.romanov@nginx.com self.load('callable', callable="app") 8151604Smax.romanov@nginx.com 8161604Smax.romanov@nginx.com assert self.get()['status'] == 200, 'callable response' 8171604Smax.romanov@nginx.com 8181695Smax.romanov@nginx.com self.load('callable', callable="blah") 8191604Smax.romanov@nginx.com 8201604Smax.romanov@nginx.com assert self.get()['status'] not in [200, 204], 'callable response inv' 8211604Smax.romanov@nginx.com 8221791Szelenkov@nginx.com def test_python_application_path(self): 8231791Szelenkov@nginx.com self.load('path') 8241791Szelenkov@nginx.com 8251791Szelenkov@nginx.com def set_path(path): 8261791Szelenkov@nginx.com assert 'success' in self.conf(path, 'applications/path/path') 8271791Szelenkov@nginx.com 8281791Szelenkov@nginx.com def get_path(): 8291791Szelenkov@nginx.com return self.get()['body'].split(os.pathsep) 8301791Szelenkov@nginx.com 8311791Szelenkov@nginx.com default_path = self.conf_get('/config/applications/path/path') 8321791Szelenkov@nginx.com assert 'success' in self.conf( 8331791Szelenkov@nginx.com {"PYTHONPATH": default_path}, 8341791Szelenkov@nginx.com '/config/applications/path/environment', 8351791Szelenkov@nginx.com ) 8361791Szelenkov@nginx.com 8371791Szelenkov@nginx.com self.conf_delete('/config/applications/path/path') 8381791Szelenkov@nginx.com sys_path = get_path() 8391791Szelenkov@nginx.com 8401791Szelenkov@nginx.com set_path('"/blah"') 8411791Szelenkov@nginx.com assert ['/blah', *sys_path] == get_path(), 'check path' 8421791Szelenkov@nginx.com 8431791Szelenkov@nginx.com set_path('"/new"') 8441791Szelenkov@nginx.com assert ['/new', *sys_path] == get_path(), 'check path update' 8451791Szelenkov@nginx.com 8461791Szelenkov@nginx.com set_path('["/blah1", "/blah2"]') 8471848Szelenkov@nginx.com assert [ 8481848Szelenkov@nginx.com '/blah1', 8491848Szelenkov@nginx.com '/blah2', 8501848Szelenkov@nginx.com *sys_path, 8511848Szelenkov@nginx.com ] == get_path(), 'check path array' 8521791Szelenkov@nginx.com 8531791Szelenkov@nginx.com def test_python_application_path_invalid(self): 8541791Szelenkov@nginx.com self.load('path') 8551791Szelenkov@nginx.com 8561791Szelenkov@nginx.com def check_path(path): 8571791Szelenkov@nginx.com assert 'error' in self.conf(path, 'applications/path/path') 8581791Szelenkov@nginx.com 8591791Szelenkov@nginx.com check_path('{}') 8601791Szelenkov@nginx.com check_path('["/blah", []]') 8611791Szelenkov@nginx.com 8621683Smax.romanov@nginx.com def test_python_application_threads(self): 8631695Smax.romanov@nginx.com self.load('threads', threads=4) 8641683Smax.romanov@nginx.com 8651683Smax.romanov@nginx.com socks = [] 8661683Smax.romanov@nginx.com 8672477Szelenkov@nginx.com for _ in range(4): 8682212Szelenkov@nginx.com sock = self.get( 8691683Smax.romanov@nginx.com headers={ 8701683Smax.romanov@nginx.com 'Host': 'localhost', 8711683Smax.romanov@nginx.com 'X-Delay': '2', 8721683Smax.romanov@nginx.com 'Connection': 'close', 8731683Smax.romanov@nginx.com }, 8741683Smax.romanov@nginx.com no_recv=True, 8751683Smax.romanov@nginx.com ) 8761683Smax.romanov@nginx.com 8771683Smax.romanov@nginx.com socks.append(sock) 8781683Smax.romanov@nginx.com 8791683Smax.romanov@nginx.com threads = set() 8801683Smax.romanov@nginx.com 8811683Smax.romanov@nginx.com for sock in socks: 8821683Smax.romanov@nginx.com resp = self.recvall(sock).decode('utf-8') 8831683Smax.romanov@nginx.com 8841683Smax.romanov@nginx.com self.log_in(resp) 8851683Smax.romanov@nginx.com 8861683Smax.romanov@nginx.com resp = self._resp_to_dict(resp) 8871683Smax.romanov@nginx.com 8881683Smax.romanov@nginx.com assert resp['status'] == 200, 'status' 8891683Smax.romanov@nginx.com 8901683Smax.romanov@nginx.com threads.add(resp['headers']['X-Thread']) 8911683Smax.romanov@nginx.com 8921683Smax.romanov@nginx.com assert resp['headers']['Wsgi-Multithread'] == 'True', 'multithread' 8931683Smax.romanov@nginx.com 8941683Smax.romanov@nginx.com sock.close() 8951683Smax.romanov@nginx.com 8961683Smax.romanov@nginx.com assert len(socks) == len(threads), 'threads differs' 897