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 17552Szelenkov@nginx.com def test_python_application_variables(self): 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' 461596Szelenkov@nginx.com assert ( 471596Szelenkov@nginx.com abs(self.date_to_sec_epoch(date) - self.sec_epoch()) < 5 481596Szelenkov@nginx.com ), 'date header' 49599Szelenkov@nginx.com 501596Szelenkov@nginx.com assert headers == { 511596Szelenkov@nginx.com 'Connection': 'close', 521596Szelenkov@nginx.com 'Content-Length': str(len(body)), 531596Szelenkov@nginx.com 'Content-Type': 'text/html', 541596Szelenkov@nginx.com 'Request-Method': 'POST', 551596Szelenkov@nginx.com 'Request-Uri': '/', 561596Szelenkov@nginx.com 'Http-Host': 'localhost', 571596Szelenkov@nginx.com 'Server-Protocol': 'HTTP/1.1', 581605Smax.romanov@nginx.com 'Custom-Header': 'blah, Blah, BLAH', 591596Szelenkov@nginx.com 'Wsgi-Version': '(1, 0)', 601596Szelenkov@nginx.com 'Wsgi-Url-Scheme': 'http', 611596Szelenkov@nginx.com 'Wsgi-Multithread': 'False', 621596Szelenkov@nginx.com 'Wsgi-Multiprocess': 'True', 631596Szelenkov@nginx.com 'Wsgi-Run-Once': 'False', 641596Szelenkov@nginx.com }, 'headers' 651596Szelenkov@nginx.com assert resp['body'] == body, 'body' 66484Szelenkov@nginx.com 67497Szelenkov@nginx.com def test_python_application_query_string(self): 68552Szelenkov@nginx.com self.load('query_string') 69497Szelenkov@nginx.com 70505Szelenkov@nginx.com resp = self.get(url='/?var1=val1&var2=val2') 71497Szelenkov@nginx.com 721596Szelenkov@nginx.com assert ( 731596Szelenkov@nginx.com resp['headers']['Query-String'] == 'var1=val1&var2=val2' 741596Szelenkov@nginx.com ), 'Query-String header' 75497Szelenkov@nginx.com 761171Svbart@nginx.com def test_python_application_query_string_space(self): 771171Svbart@nginx.com self.load('query_string') 781171Svbart@nginx.com 791171Svbart@nginx.com resp = self.get(url='/ ?var1=val1&var2=val2') 801596Szelenkov@nginx.com assert ( 811596Szelenkov@nginx.com resp['headers']['Query-String'] == 'var1=val1&var2=val2' 821596Szelenkov@nginx.com ), 'Query-String space' 831171Svbart@nginx.com 841171Svbart@nginx.com resp = self.get(url='/ %20?var1=val1&var2=val2') 851596Szelenkov@nginx.com assert ( 861596Szelenkov@nginx.com resp['headers']['Query-String'] == 'var1=val1&var2=val2' 871596Szelenkov@nginx.com ), 'Query-String space 2' 881171Svbart@nginx.com 891171Svbart@nginx.com resp = self.get(url='/ %20 ?var1=val1&var2=val2') 901596Szelenkov@nginx.com assert ( 911596Szelenkov@nginx.com resp['headers']['Query-String'] == 'var1=val1&var2=val2' 921596Szelenkov@nginx.com ), 'Query-String space 3' 931171Svbart@nginx.com 941171Svbart@nginx.com resp = self.get(url='/blah %20 blah? var1= val1 & var2=val2') 951596Szelenkov@nginx.com assert ( 961596Szelenkov@nginx.com resp['headers']['Query-String'] == ' var1= val1 & var2=val2' 971596Szelenkov@nginx.com ), 'Query-String space 4' 981171Svbart@nginx.com 992273Sjeff.iadarola@gmail.com def test_python_application_prefix(self): 1002273Sjeff.iadarola@gmail.com self.load('prefix', prefix='/api/rest') 1012273Sjeff.iadarola@gmail.com 1022273Sjeff.iadarola@gmail.com def set_prefix(prefix): 1032330Szelenkov@nginx.com self.conf(f'"{prefix}"', 'applications/prefix/prefix') 1042273Sjeff.iadarola@gmail.com 1052273Sjeff.iadarola@gmail.com def check_prefix(url, script_name, path_info): 1062273Sjeff.iadarola@gmail.com resp = self.get(url=url) 1072273Sjeff.iadarola@gmail.com assert resp['status'] == 200 1082273Sjeff.iadarola@gmail.com assert resp['headers']['Script-Name'] == script_name 1092273Sjeff.iadarola@gmail.com assert resp['headers']['Path-Info'] == path_info 1102273Sjeff.iadarola@gmail.com 1112273Sjeff.iadarola@gmail.com check_prefix('/ap', 'NULL', '/ap') 1122273Sjeff.iadarola@gmail.com check_prefix('/api', 'NULL', '/api') 1132273Sjeff.iadarola@gmail.com check_prefix('/api/', 'NULL', '/api/') 1142273Sjeff.iadarola@gmail.com check_prefix('/api/res', 'NULL', '/api/res') 1152273Sjeff.iadarola@gmail.com check_prefix('/api/restful', 'NULL', '/api/restful') 1162273Sjeff.iadarola@gmail.com check_prefix('/api/rest', '/api/rest', '') 1172273Sjeff.iadarola@gmail.com check_prefix('/api/rest/', '/api/rest', '/') 1182273Sjeff.iadarola@gmail.com check_prefix('/api/rest/get', '/api/rest', '/get') 1192273Sjeff.iadarola@gmail.com check_prefix('/api/rest/get/blah', '/api/rest', '/get/blah') 1202273Sjeff.iadarola@gmail.com 1212273Sjeff.iadarola@gmail.com set_prefix('/api/rest/') 1222273Sjeff.iadarola@gmail.com check_prefix('/api/rest', '/api/rest', '') 1232273Sjeff.iadarola@gmail.com check_prefix('/api/restful', 'NULL', '/api/restful') 1242273Sjeff.iadarola@gmail.com check_prefix('/api/rest/', '/api/rest', '/') 1252273Sjeff.iadarola@gmail.com check_prefix('/api/rest/blah', '/api/rest', '/blah') 1262273Sjeff.iadarola@gmail.com 1272273Sjeff.iadarola@gmail.com set_prefix('/app') 1282273Sjeff.iadarola@gmail.com check_prefix('/ap', 'NULL', '/ap') 1292273Sjeff.iadarola@gmail.com check_prefix('/app', '/app', '') 1302273Sjeff.iadarola@gmail.com check_prefix('/app/', '/app', '/') 1312273Sjeff.iadarola@gmail.com check_prefix('/application/', 'NULL', '/application/') 1322273Sjeff.iadarola@gmail.com 1332273Sjeff.iadarola@gmail.com set_prefix('/') 1342273Sjeff.iadarola@gmail.com check_prefix('/', 'NULL', '/') 1352273Sjeff.iadarola@gmail.com check_prefix('/app', 'NULL', '/app') 1362273Sjeff.iadarola@gmail.com 137894Szelenkov@nginx.com def test_python_application_query_string_empty(self): 138894Szelenkov@nginx.com self.load('query_string') 139894Szelenkov@nginx.com 140894Szelenkov@nginx.com resp = self.get(url='/?') 141894Szelenkov@nginx.com 1421596Szelenkov@nginx.com assert resp['status'] == 200, 'query string empty status' 1431596Szelenkov@nginx.com assert resp['headers']['Query-String'] == '', 'query string empty' 144894Szelenkov@nginx.com 145894Szelenkov@nginx.com def test_python_application_query_string_absent(self): 146894Szelenkov@nginx.com self.load('query_string') 147894Szelenkov@nginx.com 148894Szelenkov@nginx.com resp = self.get() 149894Szelenkov@nginx.com 1501596Szelenkov@nginx.com assert resp['status'] == 200, 'query string absent status' 1511596Szelenkov@nginx.com assert resp['headers']['Query-String'] == '', 'query string absent' 152894Szelenkov@nginx.com 1531596Szelenkov@nginx.com @pytest.mark.skip('not yet') 154495Szelenkov@nginx.com def test_python_application_server_port(self): 155552Szelenkov@nginx.com self.load('server_port') 156495Szelenkov@nginx.com 1571596Szelenkov@nginx.com assert ( 1581596Szelenkov@nginx.com self.get()['headers']['Server-Port'] == '7080' 1591596Szelenkov@nginx.com ), 'Server-Port header' 160484Szelenkov@nginx.com 1611596Szelenkov@nginx.com @pytest.mark.skip('not yet') 1621250Szelenkov@nginx.com def test_python_application_working_directory_invalid(self): 1631250Szelenkov@nginx.com self.load('empty') 1641250Szelenkov@nginx.com 1651596Szelenkov@nginx.com assert 'success' in self.conf( 1661596Szelenkov@nginx.com '"/blah"', 'applications/empty/working_directory' 1671596Szelenkov@nginx.com ), 'configure invalid working_directory' 1681250Szelenkov@nginx.com 1691596Szelenkov@nginx.com assert self.get()['status'] == 500, 'status' 1701250Szelenkov@nginx.com 171496Szelenkov@nginx.com def test_python_application_204_transfer_encoding(self): 172552Szelenkov@nginx.com self.load('204_no_content') 173496Szelenkov@nginx.com 1741596Szelenkov@nginx.com assert ( 1751596Szelenkov@nginx.com 'Transfer-Encoding' not in self.get()['headers'] 1761596Szelenkov@nginx.com ), '204 header transfer encoding' 177484Szelenkov@nginx.com 178602Szelenkov@nginx.com def test_python_application_ctx_iter_atexit(self): 179602Szelenkov@nginx.com self.load('ctx_iter_atexit') 180602Szelenkov@nginx.com 1812190Szelenkov@nginx.com resp = self.post(body='0123456789') 182602Szelenkov@nginx.com 1831596Szelenkov@nginx.com assert resp['status'] == 200, 'ctx iter status' 1841596Szelenkov@nginx.com assert resp['body'] == '0123456789', 'ctx iter body' 185602Szelenkov@nginx.com 1861775Szelenkov@nginx.com assert 'success' in self.conf({"listeners": {}, "applications": {}}) 187602Szelenkov@nginx.com 1881596Szelenkov@nginx.com assert ( 1891596Szelenkov@nginx.com self.wait_for_record(r'RuntimeError') is not None 1901596Szelenkov@nginx.com ), 'ctx iter atexit' 191602Szelenkov@nginx.com 192603Szelenkov@nginx.com def test_python_keepalive_body(self): 193603Szelenkov@nginx.com self.load('mirror') 194603Szelenkov@nginx.com 1951596Szelenkov@nginx.com assert self.get()['status'] == 200, 'init' 1961029Szelenkov@nginx.com 1971453Szelenkov@nginx.com body = '0123456789' * 500 1981017Szelenkov@nginx.com (resp, sock) = self.post( 1991017Szelenkov@nginx.com headers={ 2001017Szelenkov@nginx.com 'Host': 'localhost', 2011017Szelenkov@nginx.com 'Connection': 'keep-alive', 2021017Szelenkov@nginx.com }, 2031017Szelenkov@nginx.com start=True, 2041453Szelenkov@nginx.com body=body, 2051029Szelenkov@nginx.com read_timeout=1, 2061017Szelenkov@nginx.com ) 207603Szelenkov@nginx.com 2081596Szelenkov@nginx.com assert resp['body'] == body, 'keep-alive 1' 209603Szelenkov@nginx.com 2101453Szelenkov@nginx.com body = '0123456789' 2112190Szelenkov@nginx.com resp = self.post(sock=sock, body=body) 212603Szelenkov@nginx.com 2131596Szelenkov@nginx.com assert resp['body'] == body, 'keep-alive 2' 214603Szelenkov@nginx.com 215684Szelenkov@nginx.com def test_python_keepalive_reconfigure(self): 216684Szelenkov@nginx.com self.load('mirror') 217684Szelenkov@nginx.com 2181596Szelenkov@nginx.com assert self.get()['status'] == 200, 'init' 2191029Szelenkov@nginx.com 220684Szelenkov@nginx.com body = '0123456789' 221684Szelenkov@nginx.com conns = 3 222684Szelenkov@nginx.com socks = [] 223684Szelenkov@nginx.com 224684Szelenkov@nginx.com for i in range(conns): 2251017Szelenkov@nginx.com (resp, sock) = self.post( 2261017Szelenkov@nginx.com headers={ 2271017Szelenkov@nginx.com 'Host': 'localhost', 2281017Szelenkov@nginx.com 'Connection': 'keep-alive', 2291017Szelenkov@nginx.com }, 2301017Szelenkov@nginx.com start=True, 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 open' 2361695Smax.romanov@nginx.com 2371695Smax.romanov@nginx.com self.load('mirror', processes=i + 1) 238684Szelenkov@nginx.com 239684Szelenkov@nginx.com socks.append(sock) 240684Szelenkov@nginx.com 241684Szelenkov@nginx.com for i in range(conns): 2421017Szelenkov@nginx.com (resp, sock) = self.post( 2431017Szelenkov@nginx.com headers={ 2441017Szelenkov@nginx.com 'Host': 'localhost', 2451017Szelenkov@nginx.com 'Connection': 'keep-alive', 2461017Szelenkov@nginx.com }, 2471017Szelenkov@nginx.com start=True, 2481017Szelenkov@nginx.com sock=socks[i], 2491017Szelenkov@nginx.com body=body, 2501029Szelenkov@nginx.com read_timeout=1, 2511017Szelenkov@nginx.com ) 252684Szelenkov@nginx.com 2531596Szelenkov@nginx.com assert resp['body'] == body, 'keep-alive request' 2541695Smax.romanov@nginx.com 2551695Smax.romanov@nginx.com self.load('mirror', processes=i + 1) 256684Szelenkov@nginx.com 257684Szelenkov@nginx.com for i in range(conns): 2582190Szelenkov@nginx.com resp = self.post(sock=socks[i], body=body) 259684Szelenkov@nginx.com 2601596Szelenkov@nginx.com assert resp['body'] == body, 'keep-alive close' 2611695Smax.romanov@nginx.com 2621695Smax.romanov@nginx.com self.load('mirror', processes=i + 1) 263684Szelenkov@nginx.com 264750Szelenkov@nginx.com def test_python_keepalive_reconfigure_2(self): 265750Szelenkov@nginx.com self.load('mirror') 266750Szelenkov@nginx.com 2671596Szelenkov@nginx.com assert self.get()['status'] == 200, 'init' 2681029Szelenkov@nginx.com 269750Szelenkov@nginx.com body = '0123456789' 270750Szelenkov@nginx.com 2711017Szelenkov@nginx.com (resp, sock) = self.post( 2721017Szelenkov@nginx.com headers={ 2731017Szelenkov@nginx.com 'Host': 'localhost', 2741017Szelenkov@nginx.com 'Connection': 'keep-alive', 2751017Szelenkov@nginx.com }, 2761017Szelenkov@nginx.com start=True, 2771017Szelenkov@nginx.com body=body, 2781029Szelenkov@nginx.com read_timeout=1, 2791017Szelenkov@nginx.com ) 280750Szelenkov@nginx.com 2811596Szelenkov@nginx.com assert resp['body'] == body, 'reconfigure 2 keep-alive 1' 282750Szelenkov@nginx.com 283750Szelenkov@nginx.com self.load('empty') 284750Szelenkov@nginx.com 2851596Szelenkov@nginx.com assert self.get()['status'] == 200, 'init' 2861029Szelenkov@nginx.com 2872190Szelenkov@nginx.com (resp, sock) = self.post(start=True, sock=sock, body=body) 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 300603Szelenkov@nginx.com def test_python_atexit(self): 301603Szelenkov@nginx.com self.load('atexit') 302603Szelenkov@nginx.com 303603Szelenkov@nginx.com self.get() 304603Szelenkov@nginx.com 3051775Szelenkov@nginx.com assert 'success' in self.conf({"listeners": {}, "applications": {}}) 306603Szelenkov@nginx.com 3071596Szelenkov@nginx.com assert self.wait_for_record(r'At exit called\.') is not None, 'atexit' 308603Szelenkov@nginx.com 3091454Szelenkov@nginx.com def test_python_process_switch(self): 3101695Smax.romanov@nginx.com self.load('delayed', processes=2) 3111454Szelenkov@nginx.com 3121596Szelenkov@nginx.com self.get( 3131596Szelenkov@nginx.com headers={ 3141596Szelenkov@nginx.com 'Host': 'localhost', 3151596Szelenkov@nginx.com 'Content-Length': '0', 3161596Szelenkov@nginx.com 'X-Delay': '5', 3171596Szelenkov@nginx.com 'Connection': 'close', 3181596Szelenkov@nginx.com }, 3191596Szelenkov@nginx.com no_recv=True, 3201596Szelenkov@nginx.com ) 3211454Szelenkov@nginx.com 3221454Szelenkov@nginx.com headers_delay_1 = { 3231454Szelenkov@nginx.com 'Connection': 'close', 3241454Szelenkov@nginx.com 'Host': 'localhost', 3251454Szelenkov@nginx.com 'Content-Length': '0', 3261454Szelenkov@nginx.com 'X-Delay': '1', 3271454Szelenkov@nginx.com } 3281454Szelenkov@nginx.com 3291454Szelenkov@nginx.com self.get(headers=headers_delay_1, no_recv=True) 3301454Szelenkov@nginx.com 3311454Szelenkov@nginx.com time.sleep(0.5) 3321454Szelenkov@nginx.com 3331454Szelenkov@nginx.com for _ in range(10): 3341454Szelenkov@nginx.com self.get(headers=headers_delay_1, no_recv=True) 3351454Szelenkov@nginx.com 3361454Szelenkov@nginx.com self.get(headers=headers_delay_1) 3371454Szelenkov@nginx.com 3381596Szelenkov@nginx.com @pytest.mark.skip('not yet') 339603Szelenkov@nginx.com def test_python_application_start_response_exit(self): 340603Szelenkov@nginx.com self.load('start_response_exit') 341603Szelenkov@nginx.com 3421596Szelenkov@nginx.com assert self.get()['status'] == 500, 'start response exit' 343603Szelenkov@nginx.com 344603Szelenkov@nginx.com def test_python_application_input_iter(self): 345603Szelenkov@nginx.com self.load('input_iter') 346603Szelenkov@nginx.com 3471400Smax.romanov@nginx.com body = '''0123456789 3481400Smax.romanov@nginx.comnext line 3491400Smax.romanov@nginx.com 3501400Smax.romanov@nginx.comlast line''' 3511400Smax.romanov@nginx.com 3521400Smax.romanov@nginx.com resp = self.post(body=body) 3531596Szelenkov@nginx.com assert resp['body'] == body, 'input iter' 3541596Szelenkov@nginx.com assert resp['headers']['X-Lines-Count'] == '4', 'input iter lines' 3551400Smax.romanov@nginx.com 3561400Smax.romanov@nginx.com def test_python_application_input_readline(self): 3571400Smax.romanov@nginx.com self.load('input_readline') 3581400Smax.romanov@nginx.com 3591400Smax.romanov@nginx.com body = '''0123456789 3601400Smax.romanov@nginx.comnext line 3611400Smax.romanov@nginx.com 3621400Smax.romanov@nginx.comlast line''' 3631400Smax.romanov@nginx.com 3641400Smax.romanov@nginx.com resp = self.post(body=body) 3651596Szelenkov@nginx.com assert resp['body'] == body, 'input readline' 3661596Szelenkov@nginx.com assert resp['headers']['X-Lines-Count'] == '4', 'input readline lines' 3671400Smax.romanov@nginx.com 3681400Smax.romanov@nginx.com def test_python_application_input_readline_size(self): 3691400Smax.romanov@nginx.com self.load('input_readline_size') 3701400Smax.romanov@nginx.com 3711400Smax.romanov@nginx.com body = '''0123456789 3721400Smax.romanov@nginx.comnext line 3731400Smax.romanov@nginx.com 3741400Smax.romanov@nginx.comlast line''' 375603Szelenkov@nginx.com 3761596Szelenkov@nginx.com assert self.post(body=body)['body'] == body, 'input readline size' 3771596Szelenkov@nginx.com assert ( 3781596Szelenkov@nginx.com self.post(body='0123')['body'] == '0123' 3791596Szelenkov@nginx.com ), 'input readline size less' 3801400Smax.romanov@nginx.com 3811400Smax.romanov@nginx.com def test_python_application_input_readlines(self): 3821400Smax.romanov@nginx.com self.load('input_readlines') 3831400Smax.romanov@nginx.com 3841400Smax.romanov@nginx.com body = '''0123456789 3851400Smax.romanov@nginx.comnext line 3861400Smax.romanov@nginx.com 3871400Smax.romanov@nginx.comlast line''' 3881400Smax.romanov@nginx.com 3891400Smax.romanov@nginx.com resp = self.post(body=body) 3901596Szelenkov@nginx.com assert resp['body'] == body, 'input readlines' 3911596Szelenkov@nginx.com assert resp['headers']['X-Lines-Count'] == '4', 'input readlines lines' 3921400Smax.romanov@nginx.com 3931400Smax.romanov@nginx.com def test_python_application_input_readlines_huge(self): 3941400Smax.romanov@nginx.com self.load('input_readlines') 3951400Smax.romanov@nginx.com 3961400Smax.romanov@nginx.com body = ( 3971400Smax.romanov@nginx.com '''0123456789 abcdefghi 3981400Smax.romanov@nginx.comnext line: 0123456789 abcdefghi 3991400Smax.romanov@nginx.com 4001400Smax.romanov@nginx.comlast line: 987654321 4011400Smax.romanov@nginx.com''' 4021400Smax.romanov@nginx.com * 512 4031400Smax.romanov@nginx.com ) 4041400Smax.romanov@nginx.com 4051596Szelenkov@nginx.com assert ( 4061596Szelenkov@nginx.com self.post(body=body, read_buffer_size=16384)['body'] == body 4071596Szelenkov@nginx.com ), 'input readlines huge' 408603Szelenkov@nginx.com 409603Szelenkov@nginx.com def test_python_application_input_read_length(self): 410603Szelenkov@nginx.com self.load('input_read_length') 411603Szelenkov@nginx.com 412603Szelenkov@nginx.com body = '0123456789' 413603Szelenkov@nginx.com 4141017Szelenkov@nginx.com resp = self.post( 4151017Szelenkov@nginx.com headers={ 4161017Szelenkov@nginx.com 'Host': 'localhost', 4171017Szelenkov@nginx.com 'Input-Length': '5', 4181017Szelenkov@nginx.com 'Connection': 'close', 4191017Szelenkov@nginx.com }, 4201017Szelenkov@nginx.com body=body, 4211017Szelenkov@nginx.com ) 422603Szelenkov@nginx.com 4231596Szelenkov@nginx.com assert resp['body'] == body[:5], 'input read length lt body' 424603Szelenkov@nginx.com 4251017Szelenkov@nginx.com resp = self.post( 4261017Szelenkov@nginx.com headers={ 4271017Szelenkov@nginx.com 'Host': 'localhost', 4281017Szelenkov@nginx.com 'Input-Length': '15', 4291017Szelenkov@nginx.com 'Connection': 'close', 4301017Szelenkov@nginx.com }, 4311017Szelenkov@nginx.com body=body, 4321017Szelenkov@nginx.com ) 433603Szelenkov@nginx.com 4341596Szelenkov@nginx.com assert resp['body'] == body, 'input read length gt body' 435603Szelenkov@nginx.com 4361017Szelenkov@nginx.com resp = self.post( 4371017Szelenkov@nginx.com headers={ 4381017Szelenkov@nginx.com 'Host': 'localhost', 4391017Szelenkov@nginx.com 'Input-Length': '0', 4401017Szelenkov@nginx.com 'Connection': 'close', 4411017Szelenkov@nginx.com }, 4421017Szelenkov@nginx.com body=body, 4431017Szelenkov@nginx.com ) 444603Szelenkov@nginx.com 4451596Szelenkov@nginx.com assert resp['body'] == '', 'input read length zero' 446603Szelenkov@nginx.com 4471017Szelenkov@nginx.com resp = self.post( 4481017Szelenkov@nginx.com headers={ 4491017Szelenkov@nginx.com 'Host': 'localhost', 4501017Szelenkov@nginx.com 'Input-Length': '-1', 4511017Szelenkov@nginx.com 'Connection': 'close', 4521017Szelenkov@nginx.com }, 4531017Szelenkov@nginx.com body=body, 4541017Szelenkov@nginx.com ) 455603Szelenkov@nginx.com 4561596Szelenkov@nginx.com assert resp['body'] == body, 'input read length negative' 457603Szelenkov@nginx.com 4581596Szelenkov@nginx.com @pytest.mark.skip('not yet') 459603Szelenkov@nginx.com def test_python_application_errors_write(self): 460603Szelenkov@nginx.com self.load('errors_write') 461603Szelenkov@nginx.com 462603Szelenkov@nginx.com self.get() 463603Szelenkov@nginx.com 4641596Szelenkov@nginx.com assert ( 4651596Szelenkov@nginx.com self.wait_for_record(r'\[error\].+Error in application\.') 4661596Szelenkov@nginx.com is not None 4671596Szelenkov@nginx.com ), 'errors write' 468603Szelenkov@nginx.com 469603Szelenkov@nginx.com def test_python_application_body_array(self): 470603Szelenkov@nginx.com self.load('body_array') 471603Szelenkov@nginx.com 4721596Szelenkov@nginx.com assert self.get()['body'] == '0123456789', 'body array' 473603Szelenkov@nginx.com 474603Szelenkov@nginx.com def test_python_application_body_io(self): 475603Szelenkov@nginx.com self.load('body_io') 476603Szelenkov@nginx.com 4771596Szelenkov@nginx.com assert self.get()['body'] == '0123456789', 'body io' 478603Szelenkov@nginx.com 479603Szelenkov@nginx.com def test_python_application_body_io_file(self): 480603Szelenkov@nginx.com self.load('body_io_file') 481603Szelenkov@nginx.com 4821596Szelenkov@nginx.com assert self.get()['body'] == 'body\n', 'body io file' 483603Szelenkov@nginx.com 4841596Szelenkov@nginx.com @pytest.mark.skip('not yet') 4851736Szelenkov@nginx.com def test_python_application_syntax_error(self, skip_alert): 4861596Szelenkov@nginx.com skip_alert(r'Python failed to import module "wsgi"') 487603Szelenkov@nginx.com self.load('syntax_error') 488603Szelenkov@nginx.com 4891596Szelenkov@nginx.com assert self.get()['status'] == 500, 'syntax error' 490603Szelenkov@nginx.com 4911736Szelenkov@nginx.com def test_python_application_loading_error(self, skip_alert): 4921596Szelenkov@nginx.com skip_alert(r'Python failed to import module "blah"') 4931568Szelenkov@nginx.com 4941695Smax.romanov@nginx.com self.load('empty', module="blah") 4951568Szelenkov@nginx.com 4961596Szelenkov@nginx.com assert self.get()['status'] == 503, 'loading error' 4971568Szelenkov@nginx.com 498603Szelenkov@nginx.com def test_python_application_close(self): 499603Szelenkov@nginx.com self.load('close') 500603Szelenkov@nginx.com 501603Szelenkov@nginx.com self.get() 502603Szelenkov@nginx.com 5031596Szelenkov@nginx.com assert self.wait_for_record(r'Close called\.') is not None, 'close' 504603Szelenkov@nginx.com 505603Szelenkov@nginx.com def test_python_application_close_error(self): 506603Szelenkov@nginx.com self.load('close_error') 507603Szelenkov@nginx.com 508603Szelenkov@nginx.com self.get() 509603Szelenkov@nginx.com 5101596Szelenkov@nginx.com assert ( 5111596Szelenkov@nginx.com self.wait_for_record(r'Close called\.') is not None 5121596Szelenkov@nginx.com ), 'close error' 513603Szelenkov@nginx.com 514617Szelenkov@nginx.com def test_python_application_not_iterable(self): 515617Szelenkov@nginx.com self.load('not_iterable') 516617Szelenkov@nginx.com 517665Szelenkov@nginx.com self.get() 518617Szelenkov@nginx.com 5191596Szelenkov@nginx.com assert ( 5201028Szelenkov@nginx.com self.wait_for_record( 5211017Szelenkov@nginx.com r'\[error\].+the application returned not an iterable object' 5221596Szelenkov@nginx.com ) 5231596Szelenkov@nginx.com is not None 5241596Szelenkov@nginx.com ), 'not iterable' 525617Szelenkov@nginx.com 526664Szelenkov@nginx.com def test_python_application_write(self): 527664Szelenkov@nginx.com self.load('write') 528664Szelenkov@nginx.com 5291596Szelenkov@nginx.com assert self.get()['body'] == '0123456789', 'write' 530664Szelenkov@nginx.com 5312329Szelenkov@nginx.com def test_python_application_encoding(self): 5322329Szelenkov@nginx.com self.load('encoding') 5332329Szelenkov@nginx.com 5342329Szelenkov@nginx.com try: 5352329Szelenkov@nginx.com locales = ( 5362329Szelenkov@nginx.com subprocess.check_output( 5372329Szelenkov@nginx.com ['locale', '-a'], 5382329Szelenkov@nginx.com stderr=subprocess.STDOUT, 5392329Szelenkov@nginx.com ) 5402329Szelenkov@nginx.com .decode() 5412329Szelenkov@nginx.com .splitlines() 5422329Szelenkov@nginx.com ) 5432329Szelenkov@nginx.com except ( 5442329Szelenkov@nginx.com FileNotFoundError, 5452329Szelenkov@nginx.com UnicodeDecodeError, 5462329Szelenkov@nginx.com subprocess.CalledProcessError, 5472329Szelenkov@nginx.com ): 5482329Szelenkov@nginx.com pytest.skip('require locale') 5492329Szelenkov@nginx.com 5502329Szelenkov@nginx.com to_check = [ 5512329Szelenkov@nginx.com re.compile(r'.*UTF[-_]?8'), 5522329Szelenkov@nginx.com re.compile(r'.*ISO[-_]?8859[-_]?1'), 5532329Szelenkov@nginx.com ] 5542329Szelenkov@nginx.com matches = [ 5552329Szelenkov@nginx.com loc 5562329Szelenkov@nginx.com for loc in locales 5572329Szelenkov@nginx.com if any(pattern.match(loc.upper()) for pattern in to_check) 5582329Szelenkov@nginx.com ] 5592329Szelenkov@nginx.com 5602329Szelenkov@nginx.com if not matches: 5612329Szelenkov@nginx.com pytest.skip('no available locales') 5622329Szelenkov@nginx.com 5632329Szelenkov@nginx.com def unify(str): 5642329Szelenkov@nginx.com str.upper().replace('-', '').replace('_', '') 5652329Szelenkov@nginx.com 5662329Szelenkov@nginx.com for loc in matches: 5672329Szelenkov@nginx.com assert 'success' in self.conf( 5682329Szelenkov@nginx.com {"LC_CTYPE": loc, "LC_ALL": ""}, 5692329Szelenkov@nginx.com '/config/applications/encoding/environment', 5702329Szelenkov@nginx.com ) 5712329Szelenkov@nginx.com resp = self.get() 5722329Szelenkov@nginx.com assert resp['status'] == 200, 'status' 5732329Szelenkov@nginx.com assert unify(resp['headers']['X-Encoding']) == unify( 5742329Szelenkov@nginx.com loc.split('.')[-1] 5752329Szelenkov@nginx.com ) 5762329Szelenkov@nginx.com 5772329Szelenkov@nginx.com def test_python_application_unicode(self, temp_dir): 5782329Szelenkov@nginx.com try: 5792329Szelenkov@nginx.com app_type = self.get_application_type() 5802329Szelenkov@nginx.com v = version.Version(app_type.split()[-1]) 5812329Szelenkov@nginx.com if v.major != 3: 5822329Szelenkov@nginx.com raise version.InvalidVersion 5832329Szelenkov@nginx.com 5842329Szelenkov@nginx.com except version.InvalidVersion: 5852329Szelenkov@nginx.com pytest.skip('require python module version 3') 5862329Szelenkov@nginx.com 5872330Szelenkov@nginx.com venv_path = f'{temp_dir}/venv' 5882329Szelenkov@nginx.com venv.create(venv_path) 5892329Szelenkov@nginx.com 5902329Szelenkov@nginx.com self.load('unicode') 5912329Szelenkov@nginx.com assert 'success' in self.conf( 5922330Szelenkov@nginx.com f'"{venv_path}"', 5932329Szelenkov@nginx.com '/config/applications/unicode/home', 5942329Szelenkov@nginx.com ) 5952329Szelenkov@nginx.com assert ( 5962329Szelenkov@nginx.com self.get( 5972329Szelenkov@nginx.com headers={ 5982329Szelenkov@nginx.com 'Host': 'localhost', 5992329Szelenkov@nginx.com 'Temp-dir': temp_dir, 6002329Szelenkov@nginx.com 'Connection': 'close', 6012329Szelenkov@nginx.com } 6022329Szelenkov@nginx.com )['status'] 6032329Szelenkov@nginx.com == 200 6042329Szelenkov@nginx.com ) 6052329Szelenkov@nginx.com 6061261Szelenkov@nginx.com def test_python_application_threading(self): 6071261Szelenkov@nginx.com """wait_for_record() timeouts after 5s while every thread works at 6081261Szelenkov@nginx.com least 3s. So without releasing GIL test should fail. 6091261Szelenkov@nginx.com """ 6101261Szelenkov@nginx.com 6111261Szelenkov@nginx.com self.load('threading') 6121261Szelenkov@nginx.com 6131261Szelenkov@nginx.com for _ in range(10): 6141261Szelenkov@nginx.com self.get(no_recv=True) 6151261Szelenkov@nginx.com 6161596Szelenkov@nginx.com assert ( 6171804Szelenkov@nginx.com self.wait_for_record(r'\(5\) Thread: 100', wait=50) is not None 6181596Szelenkov@nginx.com ), 'last thread finished' 6191017Szelenkov@nginx.com 6201283Szelenkov@nginx.com def test_python_application_iter_exception(self): 6211283Szelenkov@nginx.com self.load('iter_exception') 6221283Szelenkov@nginx.com 6231283Szelenkov@nginx.com # Default request doesn't lead to the exception. 6241283Szelenkov@nginx.com 6251283Szelenkov@nginx.com resp = self.get( 6261283Szelenkov@nginx.com headers={ 6271283Szelenkov@nginx.com 'Host': 'localhost', 6281283Szelenkov@nginx.com 'X-Skip': '9', 6291283Szelenkov@nginx.com 'X-Chunked': '1', 6301283Szelenkov@nginx.com 'Connection': 'close', 6311283Szelenkov@nginx.com } 6321283Szelenkov@nginx.com ) 6331596Szelenkov@nginx.com assert resp['status'] == 200, 'status' 6341596Szelenkov@nginx.com assert resp['body'] == 'XXXXXXX', 'body' 6351283Szelenkov@nginx.com 6361283Szelenkov@nginx.com # Exception before start_response(). 6371283Szelenkov@nginx.com 6381596Szelenkov@nginx.com assert self.get()['status'] == 503, 'error' 6391283Szelenkov@nginx.com 6401596Szelenkov@nginx.com assert self.wait_for_record(r'Traceback') is not None, 'traceback' 6411596Szelenkov@nginx.com assert ( 6422330Szelenkov@nginx.com self.wait_for_record(r"raise Exception\('first exception'\)") 6431596Szelenkov@nginx.com is not None 6441596Szelenkov@nginx.com ), 'first exception raise' 6451596Szelenkov@nginx.com assert len(self.findall(r'Traceback')) == 1, 'traceback count 1' 6461283Szelenkov@nginx.com 6471283Szelenkov@nginx.com # Exception after start_response(), before first write(). 6481283Szelenkov@nginx.com 6491596Szelenkov@nginx.com assert ( 6501283Szelenkov@nginx.com self.get( 6511283Szelenkov@nginx.com headers={ 6521283Szelenkov@nginx.com 'Host': 'localhost', 6531283Szelenkov@nginx.com 'X-Skip': '1', 6541283Szelenkov@nginx.com 'Connection': 'close', 6551283Szelenkov@nginx.com } 6561596Szelenkov@nginx.com )['status'] 6571596Szelenkov@nginx.com == 503 6581596Szelenkov@nginx.com ), 'error 2' 6591283Szelenkov@nginx.com 6601596Szelenkov@nginx.com assert ( 6612330Szelenkov@nginx.com self.wait_for_record(r"raise Exception\('second exception'\)") 6621596Szelenkov@nginx.com is not None 6631596Szelenkov@nginx.com ), 'exception raise second' 6641596Szelenkov@nginx.com assert len(self.findall(r'Traceback')) == 2, 'traceback count 2' 6651283Szelenkov@nginx.com 6661283Szelenkov@nginx.com # Exception after first write(), before first __next__(). 6671283Szelenkov@nginx.com 6681283Szelenkov@nginx.com _, sock = self.get( 6691283Szelenkov@nginx.com headers={ 6701283Szelenkov@nginx.com 'Host': 'localhost', 6711283Szelenkov@nginx.com 'X-Skip': '2', 6721283Szelenkov@nginx.com 'Connection': 'keep-alive', 6731283Szelenkov@nginx.com }, 6741283Szelenkov@nginx.com start=True, 6751283Szelenkov@nginx.com ) 6761283Szelenkov@nginx.com 6771596Szelenkov@nginx.com assert ( 6782330Szelenkov@nginx.com self.wait_for_record(r"raise Exception\('third exception'\)") 6791596Szelenkov@nginx.com is not None 6801596Szelenkov@nginx.com ), 'exception raise third' 6811596Szelenkov@nginx.com assert len(self.findall(r'Traceback')) == 3, 'traceback count 3' 6821283Szelenkov@nginx.com 6831596Szelenkov@nginx.com assert self.get(sock=sock) == {}, 'closed connection' 6841283Szelenkov@nginx.com 6851283Szelenkov@nginx.com # Exception after first write(), before first __next__(), 6861283Szelenkov@nginx.com # chunked (incomplete body). 6871283Szelenkov@nginx.com 6881283Szelenkov@nginx.com resp = self.get( 6891283Szelenkov@nginx.com headers={ 6901283Szelenkov@nginx.com 'Host': 'localhost', 6911283Szelenkov@nginx.com 'X-Skip': '2', 6921283Szelenkov@nginx.com 'X-Chunked': '1', 6931283Szelenkov@nginx.com 'Connection': 'close', 6941295St.nateldemoura@f5.com }, 6951596Szelenkov@nginx.com raw_resp=True, 6961283Szelenkov@nginx.com ) 6971295St.nateldemoura@f5.com if resp: 6981596Szelenkov@nginx.com assert resp[-5:] != '0\r\n\r\n', 'incomplete body' 6991596Szelenkov@nginx.com assert len(self.findall(r'Traceback')) == 4, 'traceback count 4' 7001283Szelenkov@nginx.com 7011283Szelenkov@nginx.com # Exception in __next__(). 7021283Szelenkov@nginx.com 7031283Szelenkov@nginx.com _, sock = self.get( 7041283Szelenkov@nginx.com headers={ 7051283Szelenkov@nginx.com 'Host': 'localhost', 7061283Szelenkov@nginx.com 'X-Skip': '3', 7071283Szelenkov@nginx.com 'Connection': 'keep-alive', 7081283Szelenkov@nginx.com }, 7091283Szelenkov@nginx.com start=True, 7101283Szelenkov@nginx.com ) 7111283Szelenkov@nginx.com 7121596Szelenkov@nginx.com assert ( 7132330Szelenkov@nginx.com self.wait_for_record(r"raise Exception\('next exception'\)") 7141596Szelenkov@nginx.com is not None 7151596Szelenkov@nginx.com ), 'exception raise next' 7161596Szelenkov@nginx.com assert len(self.findall(r'Traceback')) == 5, 'traceback count 5' 7171283Szelenkov@nginx.com 7181596Szelenkov@nginx.com assert self.get(sock=sock) == {}, 'closed connection 2' 7191283Szelenkov@nginx.com 7201283Szelenkov@nginx.com # Exception in __next__(), chunked (incomplete body). 7211283Szelenkov@nginx.com 7221283Szelenkov@nginx.com resp = self.get( 7231283Szelenkov@nginx.com headers={ 7241283Szelenkov@nginx.com 'Host': 'localhost', 7251283Szelenkov@nginx.com 'X-Skip': '3', 7261283Szelenkov@nginx.com 'X-Chunked': '1', 7271283Szelenkov@nginx.com 'Connection': 'close', 7281295St.nateldemoura@f5.com }, 7291596Szelenkov@nginx.com raw_resp=True, 7301283Szelenkov@nginx.com ) 7311295St.nateldemoura@f5.com if resp: 7321596Szelenkov@nginx.com assert resp[-5:] != '0\r\n\r\n', 'incomplete body 2' 7331596Szelenkov@nginx.com assert len(self.findall(r'Traceback')) == 6, 'traceback count 6' 7341283Szelenkov@nginx.com 7351283Szelenkov@nginx.com # Exception before start_response() and in close(). 7361283Szelenkov@nginx.com 7371596Szelenkov@nginx.com assert ( 7381283Szelenkov@nginx.com self.get( 7391283Szelenkov@nginx.com headers={ 7401283Szelenkov@nginx.com 'Host': 'localhost', 7411283Szelenkov@nginx.com 'X-Not-Skip-Close': '1', 7421283Szelenkov@nginx.com 'Connection': 'close', 7431283Szelenkov@nginx.com } 7441596Szelenkov@nginx.com )['status'] 7451596Szelenkov@nginx.com == 503 7461596Szelenkov@nginx.com ), 'error' 7471283Szelenkov@nginx.com 7481596Szelenkov@nginx.com assert ( 7492330Szelenkov@nginx.com self.wait_for_record(r"raise Exception\('close exception'\)") 7501596Szelenkov@nginx.com is not None 7511596Szelenkov@nginx.com ), 'exception raise close' 7521596Szelenkov@nginx.com assert len(self.findall(r'Traceback')) == 8, 'traceback count 8' 7531283Szelenkov@nginx.com 7541596Szelenkov@nginx.com def test_python_user_group(self, is_su): 7551596Szelenkov@nginx.com if not is_su: 7561596Szelenkov@nginx.com pytest.skip('requires root') 7571304St.nateldemoura@f5.com 7581304St.nateldemoura@f5.com nobody_uid = pwd.getpwnam('nobody').pw_uid 7591304St.nateldemoura@f5.com 7601304St.nateldemoura@f5.com group = 'nobody' 7611304St.nateldemoura@f5.com 7621304St.nateldemoura@f5.com try: 7631304St.nateldemoura@f5.com group_id = grp.getgrnam(group).gr_gid 7641706Smax.romanov@nginx.com except KeyError: 7651304St.nateldemoura@f5.com group = 'nogroup' 7661304St.nateldemoura@f5.com group_id = grp.getgrnam(group).gr_gid 7671304St.nateldemoura@f5.com 7681304St.nateldemoura@f5.com self.load('user_group') 7691304St.nateldemoura@f5.com 7701304St.nateldemoura@f5.com obj = self.getjson()['body'] 7711596Szelenkov@nginx.com assert obj['UID'] == nobody_uid, 'nobody uid' 7721596Szelenkov@nginx.com assert obj['GID'] == group_id, 'nobody gid' 7731304St.nateldemoura@f5.com 7741304St.nateldemoura@f5.com self.load('user_group', user='nobody') 7751304St.nateldemoura@f5.com 7761304St.nateldemoura@f5.com obj = self.getjson()['body'] 7771596Szelenkov@nginx.com assert obj['UID'] == nobody_uid, 'nobody uid user=nobody' 7781596Szelenkov@nginx.com assert obj['GID'] == group_id, 'nobody gid user=nobody' 7791304St.nateldemoura@f5.com 7801304St.nateldemoura@f5.com self.load('user_group', user='nobody', group=group) 7811304St.nateldemoura@f5.com 7821304St.nateldemoura@f5.com obj = self.getjson()['body'] 7832330Szelenkov@nginx.com assert obj['UID'] == nobody_uid, f'nobody uid user=nobody group={group}' 7842330Szelenkov@nginx.com assert obj['GID'] == group_id, f'nobody gid user=nobody group={group}' 7851304St.nateldemoura@f5.com 7861304St.nateldemoura@f5.com self.load('user_group', group=group) 7871304St.nateldemoura@f5.com 7881304St.nateldemoura@f5.com obj = self.getjson()['body'] 7892330Szelenkov@nginx.com assert obj['UID'] == nobody_uid, f'nobody uid group={group}' 7902330Szelenkov@nginx.com assert obj['GID'] == group_id, f'nobody gid group={group}' 7911304St.nateldemoura@f5.com 7921304St.nateldemoura@f5.com self.load('user_group', user='root') 7931304St.nateldemoura@f5.com 7941304St.nateldemoura@f5.com obj = self.getjson()['body'] 7951596Szelenkov@nginx.com assert obj['UID'] == 0, 'root uid user=root' 7961596Szelenkov@nginx.com assert obj['GID'] == 0, 'root gid user=root' 7971304St.nateldemoura@f5.com 7981304St.nateldemoura@f5.com group = 'root' 7991304St.nateldemoura@f5.com 8001304St.nateldemoura@f5.com try: 8011304St.nateldemoura@f5.com grp.getgrnam(group) 8021304St.nateldemoura@f5.com group = True 8031706Smax.romanov@nginx.com except KeyError: 8041304St.nateldemoura@f5.com group = False 8051304St.nateldemoura@f5.com 8061304St.nateldemoura@f5.com if group: 8071304St.nateldemoura@f5.com self.load('user_group', user='root', group='root') 8081304St.nateldemoura@f5.com 8091304St.nateldemoura@f5.com obj = self.getjson()['body'] 8101596Szelenkov@nginx.com assert obj['UID'] == 0, 'root uid user=root group=root' 8111596Szelenkov@nginx.com assert obj['GID'] == 0, 'root gid user=root group=root' 8121304St.nateldemoura@f5.com 8131304St.nateldemoura@f5.com self.load('user_group', group='root') 8141304St.nateldemoura@f5.com 8151304St.nateldemoura@f5.com obj = self.getjson()['body'] 8161596Szelenkov@nginx.com assert obj['UID'] == nobody_uid, 'root uid group=root' 8171596Szelenkov@nginx.com assert obj['GID'] == 0, 'root gid group=root' 8181604Smax.romanov@nginx.com 8191736Szelenkov@nginx.com def test_python_application_callable(self, skip_alert): 8201604Smax.romanov@nginx.com skip_alert(r'Python failed to get "blah" from module') 8211604Smax.romanov@nginx.com self.load('callable') 8221604Smax.romanov@nginx.com 8231604Smax.romanov@nginx.com assert self.get()['status'] == 204, 'default application response' 8241604Smax.romanov@nginx.com 8251695Smax.romanov@nginx.com self.load('callable', callable="app") 8261604Smax.romanov@nginx.com 8271604Smax.romanov@nginx.com assert self.get()['status'] == 200, 'callable response' 8281604Smax.romanov@nginx.com 8291695Smax.romanov@nginx.com self.load('callable', callable="blah") 8301604Smax.romanov@nginx.com 8311604Smax.romanov@nginx.com assert self.get()['status'] not in [200, 204], 'callable response inv' 8321604Smax.romanov@nginx.com 8331791Szelenkov@nginx.com def test_python_application_path(self): 8341791Szelenkov@nginx.com self.load('path') 8351791Szelenkov@nginx.com 8361791Szelenkov@nginx.com def set_path(path): 8371791Szelenkov@nginx.com assert 'success' in self.conf(path, 'applications/path/path') 8381791Szelenkov@nginx.com 8391791Szelenkov@nginx.com def get_path(): 8401791Szelenkov@nginx.com return self.get()['body'].split(os.pathsep) 8411791Szelenkov@nginx.com 8421791Szelenkov@nginx.com default_path = self.conf_get('/config/applications/path/path') 8431791Szelenkov@nginx.com assert 'success' in self.conf( 8441791Szelenkov@nginx.com {"PYTHONPATH": default_path}, 8451791Szelenkov@nginx.com '/config/applications/path/environment', 8461791Szelenkov@nginx.com ) 8471791Szelenkov@nginx.com 8481791Szelenkov@nginx.com self.conf_delete('/config/applications/path/path') 8491791Szelenkov@nginx.com sys_path = get_path() 8501791Szelenkov@nginx.com 8511791Szelenkov@nginx.com set_path('"/blah"') 8521791Szelenkov@nginx.com assert ['/blah', *sys_path] == get_path(), 'check path' 8531791Szelenkov@nginx.com 8541791Szelenkov@nginx.com set_path('"/new"') 8551791Szelenkov@nginx.com assert ['/new', *sys_path] == get_path(), 'check path update' 8561791Szelenkov@nginx.com 8571791Szelenkov@nginx.com set_path('["/blah1", "/blah2"]') 8581848Szelenkov@nginx.com assert [ 8591848Szelenkov@nginx.com '/blah1', 8601848Szelenkov@nginx.com '/blah2', 8611848Szelenkov@nginx.com *sys_path, 8621848Szelenkov@nginx.com ] == get_path(), 'check path array' 8631791Szelenkov@nginx.com 8641791Szelenkov@nginx.com def test_python_application_path_invalid(self): 8651791Szelenkov@nginx.com self.load('path') 8661791Szelenkov@nginx.com 8671791Szelenkov@nginx.com def check_path(path): 8681791Szelenkov@nginx.com assert 'error' in self.conf(path, 'applications/path/path') 8691791Szelenkov@nginx.com 8701791Szelenkov@nginx.com check_path('{}') 8711791Szelenkov@nginx.com check_path('["/blah", []]') 8721791Szelenkov@nginx.com 8731683Smax.romanov@nginx.com def test_python_application_threads(self): 8741695Smax.romanov@nginx.com self.load('threads', threads=4) 8751683Smax.romanov@nginx.com 8761683Smax.romanov@nginx.com socks = [] 8771683Smax.romanov@nginx.com 878*2477Szelenkov@nginx.com for _ in range(4): 8792212Szelenkov@nginx.com sock = self.get( 8801683Smax.romanov@nginx.com headers={ 8811683Smax.romanov@nginx.com 'Host': 'localhost', 8821683Smax.romanov@nginx.com 'X-Delay': '2', 8831683Smax.romanov@nginx.com 'Connection': 'close', 8841683Smax.romanov@nginx.com }, 8851683Smax.romanov@nginx.com no_recv=True, 8861683Smax.romanov@nginx.com ) 8871683Smax.romanov@nginx.com 8881683Smax.romanov@nginx.com socks.append(sock) 8891683Smax.romanov@nginx.com 8901683Smax.romanov@nginx.com threads = set() 8911683Smax.romanov@nginx.com 8921683Smax.romanov@nginx.com for sock in socks: 8931683Smax.romanov@nginx.com resp = self.recvall(sock).decode('utf-8') 8941683Smax.romanov@nginx.com 8951683Smax.romanov@nginx.com self.log_in(resp) 8961683Smax.romanov@nginx.com 8971683Smax.romanov@nginx.com resp = self._resp_to_dict(resp) 8981683Smax.romanov@nginx.com 8991683Smax.romanov@nginx.com assert resp['status'] == 200, 'status' 9001683Smax.romanov@nginx.com 9011683Smax.romanov@nginx.com threads.add(resp['headers']['X-Thread']) 9021683Smax.romanov@nginx.com 9031683Smax.romanov@nginx.com assert resp['headers']['Wsgi-Multithread'] == 'True', 'multithread' 9041683Smax.romanov@nginx.com 9051683Smax.romanov@nginx.com sock.close() 9061683Smax.romanov@nginx.com 9071683Smax.romanov@nginx.com assert len(socks) == len(threads), 'threads differs' 908