11304St.nateldemoura@f5.comimport grp 2*1596Szelenkov@nginx.comimport pytest 31304St.nateldemoura@f5.comimport pwd 41477Szelenkov@nginx.comimport re 5899Szelenkov@nginx.comimport time 61477Szelenkov@nginx.com 71019Szelenkov@nginx.comfrom unit.applications.lang.python import TestApplicationPython 8*1596Szelenkov@nginx.comfrom conftest import skip_alert 9484Szelenkov@nginx.com 101017Szelenkov@nginx.com 111019Szelenkov@nginx.comclass TestPythonApplication(TestApplicationPython): 121467Szelenkov@nginx.com prerequisites = {'modules': {'python': 'all'}} 13484Szelenkov@nginx.com 141283Szelenkov@nginx.com def findall(self, pattern): 15*1596Szelenkov@nginx.com with open(self.temp_dir + '/unit.log', 'r', errors='ignore') as f: 161283Szelenkov@nginx.com return re.findall(pattern, f.read()) 171283Szelenkov@nginx.com 18552Szelenkov@nginx.com def test_python_application_variables(self): 19552Szelenkov@nginx.com self.load('variables') 20484Szelenkov@nginx.com 21484Szelenkov@nginx.com body = 'Test body string.' 22484Szelenkov@nginx.com 231017Szelenkov@nginx.com resp = self.post( 241017Szelenkov@nginx.com headers={ 251017Szelenkov@nginx.com 'Host': 'localhost', 261017Szelenkov@nginx.com 'Content-Type': 'text/html', 271017Szelenkov@nginx.com 'Custom-Header': 'blah', 281017Szelenkov@nginx.com 'Connection': 'close', 291017Szelenkov@nginx.com }, 301017Szelenkov@nginx.com body=body, 311017Szelenkov@nginx.com ) 32484Szelenkov@nginx.com 33*1596Szelenkov@nginx.com assert resp['status'] == 200, 'status' 34505Szelenkov@nginx.com headers = resp['headers'] 35674Szelenkov@nginx.com header_server = headers.pop('Server') 36*1596Szelenkov@nginx.com assert re.search(r'Unit/[\d\.]+', header_server), 'server header' 37*1596Szelenkov@nginx.com assert ( 38*1596Szelenkov@nginx.com headers.pop('Server-Software') == header_server 39*1596Szelenkov@nginx.com ), 'server software header' 40599Szelenkov@nginx.com 41599Szelenkov@nginx.com date = headers.pop('Date') 42*1596Szelenkov@nginx.com assert date[-4:] == ' GMT', 'date header timezone' 43*1596Szelenkov@nginx.com assert ( 44*1596Szelenkov@nginx.com abs(self.date_to_sec_epoch(date) - self.sec_epoch()) < 5 45*1596Szelenkov@nginx.com ), 'date header' 46599Szelenkov@nginx.com 47*1596Szelenkov@nginx.com assert headers == { 48*1596Szelenkov@nginx.com 'Connection': 'close', 49*1596Szelenkov@nginx.com 'Content-Length': str(len(body)), 50*1596Szelenkov@nginx.com 'Content-Type': 'text/html', 51*1596Szelenkov@nginx.com 'Request-Method': 'POST', 52*1596Szelenkov@nginx.com 'Request-Uri': '/', 53*1596Szelenkov@nginx.com 'Http-Host': 'localhost', 54*1596Szelenkov@nginx.com 'Server-Protocol': 'HTTP/1.1', 55*1596Szelenkov@nginx.com 'Custom-Header': 'blah', 56*1596Szelenkov@nginx.com 'Wsgi-Version': '(1, 0)', 57*1596Szelenkov@nginx.com 'Wsgi-Url-Scheme': 'http', 58*1596Szelenkov@nginx.com 'Wsgi-Multithread': 'False', 59*1596Szelenkov@nginx.com 'Wsgi-Multiprocess': 'True', 60*1596Szelenkov@nginx.com 'Wsgi-Run-Once': 'False', 61*1596Szelenkov@nginx.com }, 'headers' 62*1596Szelenkov@nginx.com assert resp['body'] == body, 'body' 63484Szelenkov@nginx.com 64497Szelenkov@nginx.com def test_python_application_query_string(self): 65552Szelenkov@nginx.com self.load('query_string') 66497Szelenkov@nginx.com 67505Szelenkov@nginx.com resp = self.get(url='/?var1=val1&var2=val2') 68497Szelenkov@nginx.com 69*1596Szelenkov@nginx.com assert ( 70*1596Szelenkov@nginx.com resp['headers']['Query-String'] == 'var1=val1&var2=val2' 71*1596Szelenkov@nginx.com ), 'Query-String header' 72497Szelenkov@nginx.com 731171Svbart@nginx.com def test_python_application_query_string_space(self): 741171Svbart@nginx.com self.load('query_string') 751171Svbart@nginx.com 761171Svbart@nginx.com resp = self.get(url='/ ?var1=val1&var2=val2') 77*1596Szelenkov@nginx.com assert ( 78*1596Szelenkov@nginx.com resp['headers']['Query-String'] == 'var1=val1&var2=val2' 79*1596Szelenkov@nginx.com ), 'Query-String space' 801171Svbart@nginx.com 811171Svbart@nginx.com resp = self.get(url='/ %20?var1=val1&var2=val2') 82*1596Szelenkov@nginx.com assert ( 83*1596Szelenkov@nginx.com resp['headers']['Query-String'] == 'var1=val1&var2=val2' 84*1596Szelenkov@nginx.com ), 'Query-String space 2' 851171Svbart@nginx.com 861171Svbart@nginx.com resp = self.get(url='/ %20 ?var1=val1&var2=val2') 87*1596Szelenkov@nginx.com assert ( 88*1596Szelenkov@nginx.com resp['headers']['Query-String'] == 'var1=val1&var2=val2' 89*1596Szelenkov@nginx.com ), 'Query-String space 3' 901171Svbart@nginx.com 911171Svbart@nginx.com resp = self.get(url='/blah %20 blah? var1= val1 & var2=val2') 92*1596Szelenkov@nginx.com assert ( 93*1596Szelenkov@nginx.com resp['headers']['Query-String'] == ' var1= val1 & var2=val2' 94*1596Szelenkov@nginx.com ), 'Query-String space 4' 951171Svbart@nginx.com 96894Szelenkov@nginx.com def test_python_application_query_string_empty(self): 97894Szelenkov@nginx.com self.load('query_string') 98894Szelenkov@nginx.com 99894Szelenkov@nginx.com resp = self.get(url='/?') 100894Szelenkov@nginx.com 101*1596Szelenkov@nginx.com assert resp['status'] == 200, 'query string empty status' 102*1596Szelenkov@nginx.com assert resp['headers']['Query-String'] == '', 'query string empty' 103894Szelenkov@nginx.com 104894Szelenkov@nginx.com def test_python_application_query_string_absent(self): 105894Szelenkov@nginx.com self.load('query_string') 106894Szelenkov@nginx.com 107894Szelenkov@nginx.com resp = self.get() 108894Szelenkov@nginx.com 109*1596Szelenkov@nginx.com assert resp['status'] == 200, 'query string absent status' 110*1596Szelenkov@nginx.com assert resp['headers']['Query-String'] == '', 'query string absent' 111894Szelenkov@nginx.com 112*1596Szelenkov@nginx.com @pytest.mark.skip('not yet') 113495Szelenkov@nginx.com def test_python_application_server_port(self): 114552Szelenkov@nginx.com self.load('server_port') 115495Szelenkov@nginx.com 116*1596Szelenkov@nginx.com assert ( 117*1596Szelenkov@nginx.com self.get()['headers']['Server-Port'] == '7080' 118*1596Szelenkov@nginx.com ), 'Server-Port header' 119484Szelenkov@nginx.com 120*1596Szelenkov@nginx.com @pytest.mark.skip('not yet') 1211250Szelenkov@nginx.com def test_python_application_working_directory_invalid(self): 1221250Szelenkov@nginx.com self.load('empty') 1231250Szelenkov@nginx.com 124*1596Szelenkov@nginx.com assert 'success' in self.conf( 125*1596Szelenkov@nginx.com '"/blah"', 'applications/empty/working_directory' 126*1596Szelenkov@nginx.com ), 'configure invalid working_directory' 1271250Szelenkov@nginx.com 128*1596Szelenkov@nginx.com assert self.get()['status'] == 500, 'status' 1291250Szelenkov@nginx.com 130496Szelenkov@nginx.com def test_python_application_204_transfer_encoding(self): 131552Szelenkov@nginx.com self.load('204_no_content') 132496Szelenkov@nginx.com 133*1596Szelenkov@nginx.com assert ( 134*1596Szelenkov@nginx.com 'Transfer-Encoding' not in self.get()['headers'] 135*1596Szelenkov@nginx.com ), '204 header transfer encoding' 136484Szelenkov@nginx.com 137602Szelenkov@nginx.com def test_python_application_ctx_iter_atexit(self): 138602Szelenkov@nginx.com self.load('ctx_iter_atexit') 139602Szelenkov@nginx.com 1401017Szelenkov@nginx.com resp = self.post( 1411017Szelenkov@nginx.com headers={ 1421017Szelenkov@nginx.com 'Host': 'localhost', 1431017Szelenkov@nginx.com 'Connection': 'close', 1441017Szelenkov@nginx.com 'Content-Type': 'text/html', 1451017Szelenkov@nginx.com }, 1461017Szelenkov@nginx.com body='0123456789', 1471017Szelenkov@nginx.com ) 148602Szelenkov@nginx.com 149*1596Szelenkov@nginx.com assert resp['status'] == 200, 'ctx iter status' 150*1596Szelenkov@nginx.com assert resp['body'] == '0123456789', 'ctx iter body' 151602Szelenkov@nginx.com 1521017Szelenkov@nginx.com self.conf({"listeners": {}, "applications": {}}) 153602Szelenkov@nginx.com 154602Szelenkov@nginx.com self.stop() 155602Szelenkov@nginx.com 156*1596Szelenkov@nginx.com assert ( 157*1596Szelenkov@nginx.com self.wait_for_record(r'RuntimeError') is not None 158*1596Szelenkov@nginx.com ), 'ctx iter atexit' 159602Szelenkov@nginx.com 160603Szelenkov@nginx.com def test_python_keepalive_body(self): 161603Szelenkov@nginx.com self.load('mirror') 162603Szelenkov@nginx.com 163*1596Szelenkov@nginx.com assert self.get()['status'] == 200, 'init' 1641029Szelenkov@nginx.com 1651453Szelenkov@nginx.com body = '0123456789' * 500 1661017Szelenkov@nginx.com (resp, sock) = self.post( 1671017Szelenkov@nginx.com headers={ 1681017Szelenkov@nginx.com 'Host': 'localhost', 1691017Szelenkov@nginx.com 'Connection': 'keep-alive', 1701017Szelenkov@nginx.com 'Content-Type': 'text/html', 1711017Szelenkov@nginx.com }, 1721017Szelenkov@nginx.com start=True, 1731453Szelenkov@nginx.com body=body, 1741029Szelenkov@nginx.com read_timeout=1, 1751017Szelenkov@nginx.com ) 176603Szelenkov@nginx.com 177*1596Szelenkov@nginx.com assert resp['body'] == body, 'keep-alive 1' 178603Szelenkov@nginx.com 1791453Szelenkov@nginx.com body = '0123456789' 1801017Szelenkov@nginx.com resp = self.post( 1811017Szelenkov@nginx.com headers={ 1821017Szelenkov@nginx.com 'Host': 'localhost', 1831017Szelenkov@nginx.com 'Connection': 'close', 1841017Szelenkov@nginx.com 'Content-Type': 'text/html', 1851017Szelenkov@nginx.com }, 1861017Szelenkov@nginx.com sock=sock, 1871453Szelenkov@nginx.com body=body, 1881017Szelenkov@nginx.com ) 189603Szelenkov@nginx.com 190*1596Szelenkov@nginx.com assert resp['body'] == body, 'keep-alive 2' 191603Szelenkov@nginx.com 192684Szelenkov@nginx.com def test_python_keepalive_reconfigure(self): 193*1596Szelenkov@nginx.com skip_alert( 194*1596Szelenkov@nginx.com r'pthread_mutex.+failed', 195*1596Szelenkov@nginx.com r'failed to apply', 196*1596Szelenkov@nginx.com r'process \d+ exited on signal', 1971017Szelenkov@nginx.com ) 198684Szelenkov@nginx.com self.load('mirror') 199684Szelenkov@nginx.com 200*1596Szelenkov@nginx.com assert self.get()['status'] == 200, 'init' 2011029Szelenkov@nginx.com 202684Szelenkov@nginx.com body = '0123456789' 203684Szelenkov@nginx.com conns = 3 204684Szelenkov@nginx.com socks = [] 205684Szelenkov@nginx.com 206684Szelenkov@nginx.com for i in range(conns): 2071017Szelenkov@nginx.com (resp, sock) = self.post( 2081017Szelenkov@nginx.com headers={ 2091017Szelenkov@nginx.com 'Host': 'localhost', 2101017Szelenkov@nginx.com 'Connection': 'keep-alive', 2111017Szelenkov@nginx.com 'Content-Type': 'text/html', 2121017Szelenkov@nginx.com }, 2131017Szelenkov@nginx.com start=True, 2141017Szelenkov@nginx.com body=body, 2151029Szelenkov@nginx.com read_timeout=1, 2161017Szelenkov@nginx.com ) 217684Szelenkov@nginx.com 218*1596Szelenkov@nginx.com assert resp['body'] == body, 'keep-alive open' 219*1596Szelenkov@nginx.com assert 'success' in self.conf( 220*1596Szelenkov@nginx.com str(i + 1), 'applications/mirror/processes' 221*1596Szelenkov@nginx.com ), 'reconfigure' 222684Szelenkov@nginx.com 223684Szelenkov@nginx.com socks.append(sock) 224684Szelenkov@nginx.com 225684Szelenkov@nginx.com for i in range(conns): 2261017Szelenkov@nginx.com (resp, sock) = self.post( 2271017Szelenkov@nginx.com headers={ 2281017Szelenkov@nginx.com 'Host': 'localhost', 2291017Szelenkov@nginx.com 'Connection': 'keep-alive', 2301017Szelenkov@nginx.com 'Content-Type': 'text/html', 2311017Szelenkov@nginx.com }, 2321017Szelenkov@nginx.com start=True, 2331017Szelenkov@nginx.com sock=socks[i], 2341017Szelenkov@nginx.com body=body, 2351029Szelenkov@nginx.com read_timeout=1, 2361017Szelenkov@nginx.com ) 237684Szelenkov@nginx.com 238*1596Szelenkov@nginx.com assert resp['body'] == body, 'keep-alive request' 239*1596Szelenkov@nginx.com assert 'success' in self.conf( 240*1596Szelenkov@nginx.com str(i + 1), 'applications/mirror/processes' 241*1596Szelenkov@nginx.com ), 'reconfigure 2' 242684Szelenkov@nginx.com 243684Szelenkov@nginx.com for i in range(conns): 2441017Szelenkov@nginx.com resp = self.post( 2451017Szelenkov@nginx.com headers={ 2461017Szelenkov@nginx.com 'Host': 'localhost', 2471017Szelenkov@nginx.com 'Connection': 'close', 2481017Szelenkov@nginx.com 'Content-Type': 'text/html', 2491017Szelenkov@nginx.com }, 2501017Szelenkov@nginx.com sock=socks[i], 2511017Szelenkov@nginx.com body=body, 2521017Szelenkov@nginx.com ) 253684Szelenkov@nginx.com 254*1596Szelenkov@nginx.com assert resp['body'] == body, 'keep-alive close' 255*1596Szelenkov@nginx.com assert 'success' in self.conf( 256*1596Szelenkov@nginx.com str(i + 1), 'applications/mirror/processes' 257*1596Szelenkov@nginx.com ), 'reconfigure 3' 258684Szelenkov@nginx.com 259750Szelenkov@nginx.com def test_python_keepalive_reconfigure_2(self): 260750Szelenkov@nginx.com self.load('mirror') 261750Szelenkov@nginx.com 262*1596Szelenkov@nginx.com assert self.get()['status'] == 200, 'init' 2631029Szelenkov@nginx.com 264750Szelenkov@nginx.com body = '0123456789' 265750Szelenkov@nginx.com 2661017Szelenkov@nginx.com (resp, sock) = self.post( 2671017Szelenkov@nginx.com headers={ 2681017Szelenkov@nginx.com 'Host': 'localhost', 2691017Szelenkov@nginx.com 'Connection': 'keep-alive', 2701017Szelenkov@nginx.com 'Content-Type': 'text/html', 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 277*1596Szelenkov@nginx.com assert resp['body'] == body, 'reconfigure 2 keep-alive 1' 278750Szelenkov@nginx.com 279750Szelenkov@nginx.com self.load('empty') 280750Szelenkov@nginx.com 281*1596Szelenkov@nginx.com assert self.get()['status'] == 200, 'init' 2821029Szelenkov@nginx.com 2831017Szelenkov@nginx.com (resp, sock) = self.post( 2841017Szelenkov@nginx.com headers={ 2851017Szelenkov@nginx.com 'Host': 'localhost', 2861017Szelenkov@nginx.com 'Connection': 'close', 2871017Szelenkov@nginx.com 'Content-Type': 'text/html', 2881017Szelenkov@nginx.com }, 2891017Szelenkov@nginx.com start=True, 2901017Szelenkov@nginx.com sock=sock, 2911017Szelenkov@nginx.com body=body, 2921017Szelenkov@nginx.com ) 293750Szelenkov@nginx.com 294*1596Szelenkov@nginx.com assert resp['status'] == 200, 'reconfigure 2 keep-alive 2' 295*1596Szelenkov@nginx.com assert resp['body'] == '', 'reconfigure 2 keep-alive 2 body' 296750Szelenkov@nginx.com 297*1596Szelenkov@nginx.com assert 'success' in self.conf( 298*1596Szelenkov@nginx.com {"listeners": {}, "applications": {}} 299*1596Szelenkov@nginx.com ), 'reconfigure 2 clear configuration' 300750Szelenkov@nginx.com 301750Szelenkov@nginx.com resp = self.get(sock=sock) 302750Szelenkov@nginx.com 303*1596Szelenkov@nginx.com assert resp == {}, 'reconfigure 2 keep-alive 3' 304750Szelenkov@nginx.com 305750Szelenkov@nginx.com def test_python_keepalive_reconfigure_3(self): 306750Szelenkov@nginx.com self.load('empty') 307750Szelenkov@nginx.com 308*1596Szelenkov@nginx.com assert self.get()['status'] == 200, 'init' 3091029Szelenkov@nginx.com 3101453Szelenkov@nginx.com (_, sock) = self.http( 3111017Szelenkov@nginx.com b"""GET / HTTP/1.1 3121017Szelenkov@nginx.com""", 3131017Szelenkov@nginx.com start=True, 3141017Szelenkov@nginx.com raw=True, 3151453Szelenkov@nginx.com no_recv=True, 3161017Szelenkov@nginx.com ) 317750Szelenkov@nginx.com 318*1596Szelenkov@nginx.com assert self.get()['status'] == 200 3191453Szelenkov@nginx.com 320*1596Szelenkov@nginx.com assert 'success' in self.conf( 321*1596Szelenkov@nginx.com {"listeners": {}, "applications": {}} 322*1596Szelenkov@nginx.com ), 'reconfigure 3 clear configuration' 323750Szelenkov@nginx.com 3241017Szelenkov@nginx.com resp = self.http( 3251017Szelenkov@nginx.com b"""Host: localhost 326750Szelenkov@nginx.comConnection: close 327750Szelenkov@nginx.com 3281017Szelenkov@nginx.com""", 3291017Szelenkov@nginx.com sock=sock, 3301017Szelenkov@nginx.com raw=True, 3311017Szelenkov@nginx.com ) 332750Szelenkov@nginx.com 333*1596Szelenkov@nginx.com assert resp['status'] == 200, 'reconfigure 3' 334750Szelenkov@nginx.com 335603Szelenkov@nginx.com def test_python_atexit(self): 336603Szelenkov@nginx.com self.load('atexit') 337603Szelenkov@nginx.com 338603Szelenkov@nginx.com self.get() 339603Szelenkov@nginx.com 3401017Szelenkov@nginx.com self.conf({"listeners": {}, "applications": {}}) 341603Szelenkov@nginx.com 342603Szelenkov@nginx.com self.stop() 343603Szelenkov@nginx.com 344*1596Szelenkov@nginx.com assert self.wait_for_record(r'At exit called\.') is not None, 'atexit' 345603Szelenkov@nginx.com 3461454Szelenkov@nginx.com def test_python_process_switch(self): 3471454Szelenkov@nginx.com self.load('delayed') 3481454Szelenkov@nginx.com 349*1596Szelenkov@nginx.com assert 'success' in self.conf( 350*1596Szelenkov@nginx.com '2', 'applications/delayed/processes' 351*1596Szelenkov@nginx.com ), 'configure 2 processes' 3521454Szelenkov@nginx.com 353*1596Szelenkov@nginx.com self.get( 354*1596Szelenkov@nginx.com headers={ 355*1596Szelenkov@nginx.com 'Host': 'localhost', 356*1596Szelenkov@nginx.com 'Content-Length': '0', 357*1596Szelenkov@nginx.com 'X-Delay': '5', 358*1596Szelenkov@nginx.com 'Connection': 'close', 359*1596Szelenkov@nginx.com }, 360*1596Szelenkov@nginx.com no_recv=True, 361*1596Szelenkov@nginx.com ) 3621454Szelenkov@nginx.com 3631454Szelenkov@nginx.com headers_delay_1 = { 3641454Szelenkov@nginx.com 'Connection': 'close', 3651454Szelenkov@nginx.com 'Host': 'localhost', 3661454Szelenkov@nginx.com 'Content-Length': '0', 3671454Szelenkov@nginx.com 'X-Delay': '1', 3681454Szelenkov@nginx.com } 3691454Szelenkov@nginx.com 3701454Szelenkov@nginx.com self.get(headers=headers_delay_1, no_recv=True) 3711454Szelenkov@nginx.com 3721454Szelenkov@nginx.com time.sleep(0.5) 3731454Szelenkov@nginx.com 3741454Szelenkov@nginx.com for _ in range(10): 3751454Szelenkov@nginx.com self.get(headers=headers_delay_1, no_recv=True) 3761454Szelenkov@nginx.com 3771454Szelenkov@nginx.com self.get(headers=headers_delay_1) 3781454Szelenkov@nginx.com 379*1596Szelenkov@nginx.com @pytest.mark.skip('not yet') 380603Szelenkov@nginx.com def test_python_application_start_response_exit(self): 381603Szelenkov@nginx.com self.load('start_response_exit') 382603Szelenkov@nginx.com 383*1596Szelenkov@nginx.com assert self.get()['status'] == 500, 'start response exit' 384603Szelenkov@nginx.com 385603Szelenkov@nginx.com def test_python_application_input_iter(self): 386603Szelenkov@nginx.com self.load('input_iter') 387603Szelenkov@nginx.com 3881400Smax.romanov@nginx.com body = '''0123456789 3891400Smax.romanov@nginx.comnext line 3901400Smax.romanov@nginx.com 3911400Smax.romanov@nginx.comlast line''' 3921400Smax.romanov@nginx.com 3931400Smax.romanov@nginx.com resp = self.post(body=body) 394*1596Szelenkov@nginx.com assert resp['body'] == body, 'input iter' 395*1596Szelenkov@nginx.com assert resp['headers']['X-Lines-Count'] == '4', 'input iter lines' 3961400Smax.romanov@nginx.com 3971400Smax.romanov@nginx.com def test_python_application_input_readline(self): 3981400Smax.romanov@nginx.com self.load('input_readline') 3991400Smax.romanov@nginx.com 4001400Smax.romanov@nginx.com body = '''0123456789 4011400Smax.romanov@nginx.comnext line 4021400Smax.romanov@nginx.com 4031400Smax.romanov@nginx.comlast line''' 4041400Smax.romanov@nginx.com 4051400Smax.romanov@nginx.com resp = self.post(body=body) 406*1596Szelenkov@nginx.com assert resp['body'] == body, 'input readline' 407*1596Szelenkov@nginx.com assert resp['headers']['X-Lines-Count'] == '4', 'input readline lines' 4081400Smax.romanov@nginx.com 4091400Smax.romanov@nginx.com def test_python_application_input_readline_size(self): 4101400Smax.romanov@nginx.com self.load('input_readline_size') 4111400Smax.romanov@nginx.com 4121400Smax.romanov@nginx.com body = '''0123456789 4131400Smax.romanov@nginx.comnext line 4141400Smax.romanov@nginx.com 4151400Smax.romanov@nginx.comlast line''' 416603Szelenkov@nginx.com 417*1596Szelenkov@nginx.com assert self.post(body=body)['body'] == body, 'input readline size' 418*1596Szelenkov@nginx.com assert ( 419*1596Szelenkov@nginx.com self.post(body='0123')['body'] == '0123' 420*1596Szelenkov@nginx.com ), 'input readline size less' 4211400Smax.romanov@nginx.com 4221400Smax.romanov@nginx.com def test_python_application_input_readlines(self): 4231400Smax.romanov@nginx.com self.load('input_readlines') 4241400Smax.romanov@nginx.com 4251400Smax.romanov@nginx.com body = '''0123456789 4261400Smax.romanov@nginx.comnext line 4271400Smax.romanov@nginx.com 4281400Smax.romanov@nginx.comlast line''' 4291400Smax.romanov@nginx.com 4301400Smax.romanov@nginx.com resp = self.post(body=body) 431*1596Szelenkov@nginx.com assert resp['body'] == body, 'input readlines' 432*1596Szelenkov@nginx.com assert resp['headers']['X-Lines-Count'] == '4', 'input readlines lines' 4331400Smax.romanov@nginx.com 4341400Smax.romanov@nginx.com def test_python_application_input_readlines_huge(self): 4351400Smax.romanov@nginx.com self.load('input_readlines') 4361400Smax.romanov@nginx.com 4371400Smax.romanov@nginx.com body = ( 4381400Smax.romanov@nginx.com '''0123456789 abcdefghi 4391400Smax.romanov@nginx.comnext line: 0123456789 abcdefghi 4401400Smax.romanov@nginx.com 4411400Smax.romanov@nginx.comlast line: 987654321 4421400Smax.romanov@nginx.com''' 4431400Smax.romanov@nginx.com * 512 4441400Smax.romanov@nginx.com ) 4451400Smax.romanov@nginx.com 446*1596Szelenkov@nginx.com assert ( 447*1596Szelenkov@nginx.com self.post(body=body, read_buffer_size=16384)['body'] == body 448*1596Szelenkov@nginx.com ), 'input readlines huge' 449603Szelenkov@nginx.com 450603Szelenkov@nginx.com def test_python_application_input_read_length(self): 451603Szelenkov@nginx.com self.load('input_read_length') 452603Szelenkov@nginx.com 453603Szelenkov@nginx.com body = '0123456789' 454603Szelenkov@nginx.com 4551017Szelenkov@nginx.com resp = self.post( 4561017Szelenkov@nginx.com headers={ 4571017Szelenkov@nginx.com 'Host': 'localhost', 4581017Szelenkov@nginx.com 'Input-Length': '5', 4591017Szelenkov@nginx.com 'Connection': 'close', 4601017Szelenkov@nginx.com }, 4611017Szelenkov@nginx.com body=body, 4621017Szelenkov@nginx.com ) 463603Szelenkov@nginx.com 464*1596Szelenkov@nginx.com assert resp['body'] == body[:5], 'input read length lt body' 465603Szelenkov@nginx.com 4661017Szelenkov@nginx.com resp = self.post( 4671017Szelenkov@nginx.com headers={ 4681017Szelenkov@nginx.com 'Host': 'localhost', 4691017Szelenkov@nginx.com 'Input-Length': '15', 4701017Szelenkov@nginx.com 'Connection': 'close', 4711017Szelenkov@nginx.com }, 4721017Szelenkov@nginx.com body=body, 4731017Szelenkov@nginx.com ) 474603Szelenkov@nginx.com 475*1596Szelenkov@nginx.com assert resp['body'] == body, 'input read length gt body' 476603Szelenkov@nginx.com 4771017Szelenkov@nginx.com resp = self.post( 4781017Szelenkov@nginx.com headers={ 4791017Szelenkov@nginx.com 'Host': 'localhost', 4801017Szelenkov@nginx.com 'Input-Length': '0', 4811017Szelenkov@nginx.com 'Connection': 'close', 4821017Szelenkov@nginx.com }, 4831017Szelenkov@nginx.com body=body, 4841017Szelenkov@nginx.com ) 485603Szelenkov@nginx.com 486*1596Szelenkov@nginx.com assert resp['body'] == '', 'input read length zero' 487603Szelenkov@nginx.com 4881017Szelenkov@nginx.com resp = self.post( 4891017Szelenkov@nginx.com headers={ 4901017Szelenkov@nginx.com 'Host': 'localhost', 4911017Szelenkov@nginx.com 'Input-Length': '-1', 4921017Szelenkov@nginx.com 'Connection': 'close', 4931017Szelenkov@nginx.com }, 4941017Szelenkov@nginx.com body=body, 4951017Szelenkov@nginx.com ) 496603Szelenkov@nginx.com 497*1596Szelenkov@nginx.com assert resp['body'] == body, 'input read length negative' 498603Szelenkov@nginx.com 499*1596Szelenkov@nginx.com @pytest.mark.skip('not yet') 500603Szelenkov@nginx.com def test_python_application_errors_write(self): 501603Szelenkov@nginx.com self.load('errors_write') 502603Szelenkov@nginx.com 503603Szelenkov@nginx.com self.get() 504603Szelenkov@nginx.com 505603Szelenkov@nginx.com self.stop() 506603Szelenkov@nginx.com 507*1596Szelenkov@nginx.com assert ( 508*1596Szelenkov@nginx.com self.wait_for_record(r'\[error\].+Error in application\.') 509*1596Szelenkov@nginx.com is not None 510*1596Szelenkov@nginx.com ), 'errors write' 511603Szelenkov@nginx.com 512603Szelenkov@nginx.com def test_python_application_body_array(self): 513603Szelenkov@nginx.com self.load('body_array') 514603Szelenkov@nginx.com 515*1596Szelenkov@nginx.com assert self.get()['body'] == '0123456789', 'body array' 516603Szelenkov@nginx.com 517603Szelenkov@nginx.com def test_python_application_body_io(self): 518603Szelenkov@nginx.com self.load('body_io') 519603Szelenkov@nginx.com 520*1596Szelenkov@nginx.com assert self.get()['body'] == '0123456789', 'body io' 521603Szelenkov@nginx.com 522603Szelenkov@nginx.com def test_python_application_body_io_file(self): 523603Szelenkov@nginx.com self.load('body_io_file') 524603Szelenkov@nginx.com 525*1596Szelenkov@nginx.com assert self.get()['body'] == 'body\n', 'body io file' 526603Szelenkov@nginx.com 527*1596Szelenkov@nginx.com @pytest.mark.skip('not yet') 528603Szelenkov@nginx.com def test_python_application_syntax_error(self): 529*1596Szelenkov@nginx.com skip_alert(r'Python failed to import module "wsgi"') 530603Szelenkov@nginx.com self.load('syntax_error') 531603Szelenkov@nginx.com 532*1596Szelenkov@nginx.com assert self.get()['status'] == 500, 'syntax error' 533603Szelenkov@nginx.com 5341568Szelenkov@nginx.com def test_python_application_loading_error(self): 535*1596Szelenkov@nginx.com skip_alert(r'Python failed to import module "blah"') 5361568Szelenkov@nginx.com 5371568Szelenkov@nginx.com self.load('empty') 5381568Szelenkov@nginx.com 539*1596Szelenkov@nginx.com assert 'success' in self.conf('"blah"', 'applications/empty/module') 5401568Szelenkov@nginx.com 541*1596Szelenkov@nginx.com assert self.get()['status'] == 503, 'loading error' 5421568Szelenkov@nginx.com 543603Szelenkov@nginx.com def test_python_application_close(self): 544603Szelenkov@nginx.com self.load('close') 545603Szelenkov@nginx.com 546603Szelenkov@nginx.com self.get() 547603Szelenkov@nginx.com 548603Szelenkov@nginx.com self.stop() 549603Szelenkov@nginx.com 550*1596Szelenkov@nginx.com assert self.wait_for_record(r'Close called\.') is not None, 'close' 551603Szelenkov@nginx.com 552603Szelenkov@nginx.com def test_python_application_close_error(self): 553603Szelenkov@nginx.com self.load('close_error') 554603Szelenkov@nginx.com 555603Szelenkov@nginx.com self.get() 556603Szelenkov@nginx.com 557603Szelenkov@nginx.com self.stop() 558603Szelenkov@nginx.com 559*1596Szelenkov@nginx.com assert ( 560*1596Szelenkov@nginx.com self.wait_for_record(r'Close called\.') is not None 561*1596Szelenkov@nginx.com ), 'close error' 562603Szelenkov@nginx.com 563617Szelenkov@nginx.com def test_python_application_not_iterable(self): 564617Szelenkov@nginx.com self.load('not_iterable') 565617Szelenkov@nginx.com 566665Szelenkov@nginx.com self.get() 567617Szelenkov@nginx.com 568617Szelenkov@nginx.com self.stop() 569617Szelenkov@nginx.com 570*1596Szelenkov@nginx.com assert ( 5711028Szelenkov@nginx.com self.wait_for_record( 5721017Szelenkov@nginx.com r'\[error\].+the application returned not an iterable object' 573*1596Szelenkov@nginx.com ) 574*1596Szelenkov@nginx.com is not None 575*1596Szelenkov@nginx.com ), 'not iterable' 576617Szelenkov@nginx.com 577664Szelenkov@nginx.com def test_python_application_write(self): 578664Szelenkov@nginx.com self.load('write') 579664Szelenkov@nginx.com 580*1596Szelenkov@nginx.com assert self.get()['body'] == '0123456789', 'write' 581664Szelenkov@nginx.com 5821261Szelenkov@nginx.com def test_python_application_threading(self): 5831261Szelenkov@nginx.com """wait_for_record() timeouts after 5s while every thread works at 5841261Szelenkov@nginx.com least 3s. So without releasing GIL test should fail. 5851261Szelenkov@nginx.com """ 5861261Szelenkov@nginx.com 5871261Szelenkov@nginx.com self.load('threading') 5881261Szelenkov@nginx.com 5891261Szelenkov@nginx.com for _ in range(10): 5901261Szelenkov@nginx.com self.get(no_recv=True) 5911261Szelenkov@nginx.com 592*1596Szelenkov@nginx.com assert ( 593*1596Szelenkov@nginx.com self.wait_for_record(r'\(5\) Thread: 100') is not None 594*1596Szelenkov@nginx.com ), 'last thread finished' 5951017Szelenkov@nginx.com 5961283Szelenkov@nginx.com def test_python_application_iter_exception(self): 5971283Szelenkov@nginx.com self.load('iter_exception') 5981283Szelenkov@nginx.com 5991283Szelenkov@nginx.com # Default request doesn't lead to the exception. 6001283Szelenkov@nginx.com 6011283Szelenkov@nginx.com resp = self.get( 6021283Szelenkov@nginx.com headers={ 6031283Szelenkov@nginx.com 'Host': 'localhost', 6041283Szelenkov@nginx.com 'X-Skip': '9', 6051283Szelenkov@nginx.com 'X-Chunked': '1', 6061283Szelenkov@nginx.com 'Connection': 'close', 6071283Szelenkov@nginx.com } 6081283Szelenkov@nginx.com ) 609*1596Szelenkov@nginx.com assert resp['status'] == 200, 'status' 610*1596Szelenkov@nginx.com assert resp['body'] == 'XXXXXXX', 'body' 6111283Szelenkov@nginx.com 6121283Szelenkov@nginx.com # Exception before start_response(). 6131283Szelenkov@nginx.com 614*1596Szelenkov@nginx.com assert self.get()['status'] == 503, 'error' 6151283Szelenkov@nginx.com 616*1596Szelenkov@nginx.com assert self.wait_for_record(r'Traceback') is not None, 'traceback' 617*1596Szelenkov@nginx.com assert ( 618*1596Szelenkov@nginx.com self.wait_for_record(r'raise Exception\(\'first exception\'\)') 619*1596Szelenkov@nginx.com is not None 620*1596Szelenkov@nginx.com ), 'first exception raise' 621*1596Szelenkov@nginx.com assert len(self.findall(r'Traceback')) == 1, 'traceback count 1' 6221283Szelenkov@nginx.com 6231283Szelenkov@nginx.com # Exception after start_response(), before first write(). 6241283Szelenkov@nginx.com 625*1596Szelenkov@nginx.com assert ( 6261283Szelenkov@nginx.com self.get( 6271283Szelenkov@nginx.com headers={ 6281283Szelenkov@nginx.com 'Host': 'localhost', 6291283Szelenkov@nginx.com 'X-Skip': '1', 6301283Szelenkov@nginx.com 'Connection': 'close', 6311283Szelenkov@nginx.com } 632*1596Szelenkov@nginx.com )['status'] 633*1596Szelenkov@nginx.com == 503 634*1596Szelenkov@nginx.com ), 'error 2' 6351283Szelenkov@nginx.com 636*1596Szelenkov@nginx.com assert ( 637*1596Szelenkov@nginx.com self.wait_for_record(r'raise Exception\(\'second exception\'\)') 638*1596Szelenkov@nginx.com is not None 639*1596Szelenkov@nginx.com ), 'exception raise second' 640*1596Szelenkov@nginx.com assert len(self.findall(r'Traceback')) == 2, 'traceback count 2' 6411283Szelenkov@nginx.com 6421283Szelenkov@nginx.com # Exception after first write(), before first __next__(). 6431283Szelenkov@nginx.com 6441283Szelenkov@nginx.com _, sock = self.get( 6451283Szelenkov@nginx.com headers={ 6461283Szelenkov@nginx.com 'Host': 'localhost', 6471283Szelenkov@nginx.com 'X-Skip': '2', 6481283Szelenkov@nginx.com 'Connection': 'keep-alive', 6491283Szelenkov@nginx.com }, 6501283Szelenkov@nginx.com start=True, 6511283Szelenkov@nginx.com ) 6521283Szelenkov@nginx.com 653*1596Szelenkov@nginx.com assert ( 654*1596Szelenkov@nginx.com self.wait_for_record(r'raise Exception\(\'third exception\'\)') 655*1596Szelenkov@nginx.com is not None 656*1596Szelenkov@nginx.com ), 'exception raise third' 657*1596Szelenkov@nginx.com assert len(self.findall(r'Traceback')) == 3, 'traceback count 3' 6581283Szelenkov@nginx.com 659*1596Szelenkov@nginx.com assert self.get(sock=sock) == {}, 'closed connection' 6601283Szelenkov@nginx.com 6611283Szelenkov@nginx.com # Exception after first write(), before first __next__(), 6621283Szelenkov@nginx.com # chunked (incomplete body). 6631283Szelenkov@nginx.com 6641283Szelenkov@nginx.com resp = self.get( 6651283Szelenkov@nginx.com headers={ 6661283Szelenkov@nginx.com 'Host': 'localhost', 6671283Szelenkov@nginx.com 'X-Skip': '2', 6681283Szelenkov@nginx.com 'X-Chunked': '1', 6691283Szelenkov@nginx.com 'Connection': 'close', 6701295St.nateldemoura@f5.com }, 671*1596Szelenkov@nginx.com raw_resp=True, 6721283Szelenkov@nginx.com ) 6731295St.nateldemoura@f5.com if resp: 674*1596Szelenkov@nginx.com assert resp[-5:] != '0\r\n\r\n', 'incomplete body' 675*1596Szelenkov@nginx.com assert len(self.findall(r'Traceback')) == 4, 'traceback count 4' 6761283Szelenkov@nginx.com 6771283Szelenkov@nginx.com # Exception in __next__(). 6781283Szelenkov@nginx.com 6791283Szelenkov@nginx.com _, sock = self.get( 6801283Szelenkov@nginx.com headers={ 6811283Szelenkov@nginx.com 'Host': 'localhost', 6821283Szelenkov@nginx.com 'X-Skip': '3', 6831283Szelenkov@nginx.com 'Connection': 'keep-alive', 6841283Szelenkov@nginx.com }, 6851283Szelenkov@nginx.com start=True, 6861283Szelenkov@nginx.com ) 6871283Szelenkov@nginx.com 688*1596Szelenkov@nginx.com assert ( 689*1596Szelenkov@nginx.com self.wait_for_record(r'raise Exception\(\'next exception\'\)') 690*1596Szelenkov@nginx.com is not None 691*1596Szelenkov@nginx.com ), 'exception raise next' 692*1596Szelenkov@nginx.com assert len(self.findall(r'Traceback')) == 5, 'traceback count 5' 6931283Szelenkov@nginx.com 694*1596Szelenkov@nginx.com assert self.get(sock=sock) == {}, 'closed connection 2' 6951283Szelenkov@nginx.com 6961283Szelenkov@nginx.com # Exception in __next__(), chunked (incomplete body). 6971283Szelenkov@nginx.com 6981283Szelenkov@nginx.com resp = self.get( 6991283Szelenkov@nginx.com headers={ 7001283Szelenkov@nginx.com 'Host': 'localhost', 7011283Szelenkov@nginx.com 'X-Skip': '3', 7021283Szelenkov@nginx.com 'X-Chunked': '1', 7031283Szelenkov@nginx.com 'Connection': 'close', 7041295St.nateldemoura@f5.com }, 705*1596Szelenkov@nginx.com raw_resp=True, 7061283Szelenkov@nginx.com ) 7071295St.nateldemoura@f5.com if resp: 708*1596Szelenkov@nginx.com assert resp[-5:] != '0\r\n\r\n', 'incomplete body 2' 709*1596Szelenkov@nginx.com assert len(self.findall(r'Traceback')) == 6, 'traceback count 6' 7101283Szelenkov@nginx.com 7111283Szelenkov@nginx.com # Exception before start_response() and in close(). 7121283Szelenkov@nginx.com 713*1596Szelenkov@nginx.com assert ( 7141283Szelenkov@nginx.com self.get( 7151283Szelenkov@nginx.com headers={ 7161283Szelenkov@nginx.com 'Host': 'localhost', 7171283Szelenkov@nginx.com 'X-Not-Skip-Close': '1', 7181283Szelenkov@nginx.com 'Connection': 'close', 7191283Szelenkov@nginx.com } 720*1596Szelenkov@nginx.com )['status'] 721*1596Szelenkov@nginx.com == 503 722*1596Szelenkov@nginx.com ), 'error' 7231283Szelenkov@nginx.com 724*1596Szelenkov@nginx.com assert ( 725*1596Szelenkov@nginx.com self.wait_for_record(r'raise Exception\(\'close exception\'\)') 726*1596Szelenkov@nginx.com is not None 727*1596Szelenkov@nginx.com ), 'exception raise close' 728*1596Szelenkov@nginx.com assert len(self.findall(r'Traceback')) == 8, 'traceback count 8' 7291283Szelenkov@nginx.com 730*1596Szelenkov@nginx.com def test_python_user_group(self, is_su): 731*1596Szelenkov@nginx.com if not is_su: 732*1596Szelenkov@nginx.com pytest.skip('requires root') 7331304St.nateldemoura@f5.com 7341304St.nateldemoura@f5.com nobody_uid = pwd.getpwnam('nobody').pw_uid 7351304St.nateldemoura@f5.com 7361304St.nateldemoura@f5.com group = 'nobody' 7371304St.nateldemoura@f5.com 7381304St.nateldemoura@f5.com try: 7391304St.nateldemoura@f5.com group_id = grp.getgrnam(group).gr_gid 7401304St.nateldemoura@f5.com except: 7411304St.nateldemoura@f5.com group = 'nogroup' 7421304St.nateldemoura@f5.com group_id = grp.getgrnam(group).gr_gid 7431304St.nateldemoura@f5.com 7441304St.nateldemoura@f5.com self.load('user_group') 7451304St.nateldemoura@f5.com 7461304St.nateldemoura@f5.com obj = self.getjson()['body'] 747*1596Szelenkov@nginx.com assert obj['UID'] == nobody_uid, 'nobody uid' 748*1596Szelenkov@nginx.com assert obj['GID'] == group_id, 'nobody gid' 7491304St.nateldemoura@f5.com 7501304St.nateldemoura@f5.com self.load('user_group', user='nobody') 7511304St.nateldemoura@f5.com 7521304St.nateldemoura@f5.com obj = self.getjson()['body'] 753*1596Szelenkov@nginx.com assert obj['UID'] == nobody_uid, 'nobody uid user=nobody' 754*1596Szelenkov@nginx.com assert obj['GID'] == group_id, 'nobody gid user=nobody' 7551304St.nateldemoura@f5.com 7561304St.nateldemoura@f5.com self.load('user_group', user='nobody', group=group) 7571304St.nateldemoura@f5.com 7581304St.nateldemoura@f5.com obj = self.getjson()['body'] 759*1596Szelenkov@nginx.com assert obj['UID'] == nobody_uid, ( 760*1596Szelenkov@nginx.com 'nobody uid user=nobody group=%s' % group 7611304St.nateldemoura@f5.com ) 7621304St.nateldemoura@f5.com 763*1596Szelenkov@nginx.com assert obj['GID'] == group_id, ( 764*1596Szelenkov@nginx.com 'nobody gid user=nobody group=%s' % group 7651304St.nateldemoura@f5.com ) 7661304St.nateldemoura@f5.com 7671304St.nateldemoura@f5.com self.load('user_group', group=group) 7681304St.nateldemoura@f5.com 7691304St.nateldemoura@f5.com obj = self.getjson()['body'] 770*1596Szelenkov@nginx.com assert obj['UID'] == nobody_uid, 'nobody uid group=%s' % group 7711304St.nateldemoura@f5.com 772*1596Szelenkov@nginx.com assert obj['GID'] == group_id, 'nobody gid group=%s' % group 7731304St.nateldemoura@f5.com 7741304St.nateldemoura@f5.com self.load('user_group', user='root') 7751304St.nateldemoura@f5.com 7761304St.nateldemoura@f5.com obj = self.getjson()['body'] 777*1596Szelenkov@nginx.com assert obj['UID'] == 0, 'root uid user=root' 778*1596Szelenkov@nginx.com assert obj['GID'] == 0, 'root gid user=root' 7791304St.nateldemoura@f5.com 7801304St.nateldemoura@f5.com group = 'root' 7811304St.nateldemoura@f5.com 7821304St.nateldemoura@f5.com try: 7831304St.nateldemoura@f5.com grp.getgrnam(group) 7841304St.nateldemoura@f5.com group = True 7851304St.nateldemoura@f5.com except: 7861304St.nateldemoura@f5.com group = False 7871304St.nateldemoura@f5.com 7881304St.nateldemoura@f5.com if group: 7891304St.nateldemoura@f5.com self.load('user_group', user='root', group='root') 7901304St.nateldemoura@f5.com 7911304St.nateldemoura@f5.com obj = self.getjson()['body'] 792*1596Szelenkov@nginx.com assert obj['UID'] == 0, 'root uid user=root group=root' 793*1596Szelenkov@nginx.com assert obj['GID'] == 0, 'root gid user=root group=root' 7941304St.nateldemoura@f5.com 7951304St.nateldemoura@f5.com self.load('user_group', group='root') 7961304St.nateldemoura@f5.com 7971304St.nateldemoura@f5.com obj = self.getjson()['body'] 798*1596Szelenkov@nginx.com assert obj['UID'] == nobody_uid, 'root uid group=root' 799*1596Szelenkov@nginx.com assert obj['GID'] == 0, 'root gid group=root' 800