1*1283Szelenkov@nginx.comimport re
2899Szelenkov@nginx.comimport time
3484Szelenkov@nginx.comimport unittest
41019Szelenkov@nginx.comfrom unit.applications.lang.python import TestApplicationPython
5484Szelenkov@nginx.com
61017Szelenkov@nginx.com
71019Szelenkov@nginx.comclass TestPythonApplication(TestApplicationPython):
81165Szelenkov@nginx.com    prerequisites = {'modules': ['python']}
9484Szelenkov@nginx.com
10*1283Szelenkov@nginx.com    def findall(self, pattern):
11*1283Szelenkov@nginx.com        with open(self.testdir + '/unit.log', 'r', errors='ignore') as f:
12*1283Szelenkov@nginx.com            return re.findall(pattern, f.read())
13*1283Szelenkov@nginx.com
14552Szelenkov@nginx.com    def test_python_application_variables(self):
15552Szelenkov@nginx.com        self.load('variables')
16484Szelenkov@nginx.com
17484Szelenkov@nginx.com        body = 'Test body string.'
18484Szelenkov@nginx.com
191017Szelenkov@nginx.com        resp = self.post(
201017Szelenkov@nginx.com            headers={
211017Szelenkov@nginx.com                'Host': 'localhost',
221017Szelenkov@nginx.com                'Content-Type': 'text/html',
231017Szelenkov@nginx.com                'Custom-Header': 'blah',
241017Szelenkov@nginx.com                'Connection': 'close',
251017Szelenkov@nginx.com            },
261017Szelenkov@nginx.com            body=body,
271017Szelenkov@nginx.com        )
28484Szelenkov@nginx.com
29505Szelenkov@nginx.com        self.assertEqual(resp['status'], 200, 'status')
30505Szelenkov@nginx.com        headers = resp['headers']
31674Szelenkov@nginx.com        header_server = headers.pop('Server')
32674Szelenkov@nginx.com        self.assertRegex(header_server, r'Unit/[\d\.]+', 'server header')
331017Szelenkov@nginx.com        self.assertEqual(
341017Szelenkov@nginx.com            headers.pop('Server-Software'),
351017Szelenkov@nginx.com            header_server,
361017Szelenkov@nginx.com            'server software header',
371017Szelenkov@nginx.com        )
38599Szelenkov@nginx.com
39599Szelenkov@nginx.com        date = headers.pop('Date')
40599Szelenkov@nginx.com        self.assertEqual(date[-4:], ' GMT', 'date header timezone')
411017Szelenkov@nginx.com        self.assertLess(
421017Szelenkov@nginx.com            abs(self.date_to_sec_epoch(date) - self.sec_epoch()),
431017Szelenkov@nginx.com            5,
441017Szelenkov@nginx.com            'date header',
451017Szelenkov@nginx.com        )
46599Szelenkov@nginx.com
471017Szelenkov@nginx.com        self.assertDictEqual(
481017Szelenkov@nginx.com            headers,
491017Szelenkov@nginx.com            {
501017Szelenkov@nginx.com                'Connection': 'close',
511017Szelenkov@nginx.com                'Content-Length': str(len(body)),
521017Szelenkov@nginx.com                'Content-Type': 'text/html',
531017Szelenkov@nginx.com                'Request-Method': 'POST',
541017Szelenkov@nginx.com                'Request-Uri': '/',
551017Szelenkov@nginx.com                'Http-Host': 'localhost',
561017Szelenkov@nginx.com                'Server-Protocol': 'HTTP/1.1',
571017Szelenkov@nginx.com                'Custom-Header': 'blah',
581017Szelenkov@nginx.com                'Wsgi-Version': '(1, 0)',
591017Szelenkov@nginx.com                'Wsgi-Url-Scheme': 'http',
601017Szelenkov@nginx.com                'Wsgi-Multithread': 'False',
611017Szelenkov@nginx.com                'Wsgi-Multiprocess': 'True',
621017Szelenkov@nginx.com                'Wsgi-Run-Once': 'False',
631017Szelenkov@nginx.com            },
641017Szelenkov@nginx.com            'headers',
651017Szelenkov@nginx.com        )
66505Szelenkov@nginx.com        self.assertEqual(resp['body'], body, 'body')
67484Szelenkov@nginx.com
68497Szelenkov@nginx.com    def test_python_application_query_string(self):
69552Szelenkov@nginx.com        self.load('query_string')
70497Szelenkov@nginx.com
71505Szelenkov@nginx.com        resp = self.get(url='/?var1=val1&var2=val2')
72497Szelenkov@nginx.com
731017Szelenkov@nginx.com        self.assertEqual(
741017Szelenkov@nginx.com            resp['headers']['Query-String'],
751017Szelenkov@nginx.com            'var1=val1&var2=val2',
761017Szelenkov@nginx.com            'Query-String header',
771017Szelenkov@nginx.com        )
78497Szelenkov@nginx.com
791171Svbart@nginx.com    def test_python_application_query_string_space(self):
801171Svbart@nginx.com        self.load('query_string')
811171Svbart@nginx.com
821171Svbart@nginx.com        resp = self.get(url='/ ?var1=val1&var2=val2')
831171Svbart@nginx.com        self.assertEqual(
841171Svbart@nginx.com            resp['headers']['Query-String'],
851171Svbart@nginx.com            'var1=val1&var2=val2',
861171Svbart@nginx.com            'Query-String space',
871171Svbart@nginx.com        )
881171Svbart@nginx.com
891171Svbart@nginx.com        resp = self.get(url='/ %20?var1=val1&var2=val2')
901171Svbart@nginx.com        self.assertEqual(
911171Svbart@nginx.com            resp['headers']['Query-String'],
921171Svbart@nginx.com            'var1=val1&var2=val2',
931171Svbart@nginx.com            'Query-String space 2',
941171Svbart@nginx.com        )
951171Svbart@nginx.com
961171Svbart@nginx.com        resp = self.get(url='/ %20 ?var1=val1&var2=val2')
971171Svbart@nginx.com        self.assertEqual(
981171Svbart@nginx.com            resp['headers']['Query-String'],
991171Svbart@nginx.com            'var1=val1&var2=val2',
1001171Svbart@nginx.com            'Query-String space 3',
1011171Svbart@nginx.com        )
1021171Svbart@nginx.com
1031171Svbart@nginx.com        resp = self.get(url='/blah %20 blah? var1= val1 & var2=val2')
1041171Svbart@nginx.com        self.assertEqual(
1051171Svbart@nginx.com            resp['headers']['Query-String'],
1061171Svbart@nginx.com            ' var1= val1 & var2=val2',
1071171Svbart@nginx.com            'Query-String space 4',
1081171Svbart@nginx.com        )
1091171Svbart@nginx.com
110894Szelenkov@nginx.com    def test_python_application_query_string_empty(self):
111894Szelenkov@nginx.com        self.load('query_string')
112894Szelenkov@nginx.com
113894Szelenkov@nginx.com        resp = self.get(url='/?')
114894Szelenkov@nginx.com
115894Szelenkov@nginx.com        self.assertEqual(resp['status'], 200, 'query string empty status')
1161017Szelenkov@nginx.com        self.assertEqual(
1171017Szelenkov@nginx.com            resp['headers']['Query-String'], '', 'query string empty'
1181017Szelenkov@nginx.com        )
119894Szelenkov@nginx.com
120894Szelenkov@nginx.com    def test_python_application_query_string_absent(self):
121894Szelenkov@nginx.com        self.load('query_string')
122894Szelenkov@nginx.com
123894Szelenkov@nginx.com        resp = self.get()
124894Szelenkov@nginx.com
125894Szelenkov@nginx.com        self.assertEqual(resp['status'], 200, 'query string absent status')
1261017Szelenkov@nginx.com        self.assertEqual(
1271017Szelenkov@nginx.com            resp['headers']['Query-String'], '', 'query string absent'
1281017Szelenkov@nginx.com        )
129894Szelenkov@nginx.com
1301064Szelenkov@nginx.com    @unittest.skip('not yet')
131495Szelenkov@nginx.com    def test_python_application_server_port(self):
132552Szelenkov@nginx.com        self.load('server_port')
133495Szelenkov@nginx.com
1341017Szelenkov@nginx.com        self.assertEqual(
1351017Szelenkov@nginx.com            self.get()['headers']['Server-Port'], '7080', 'Server-Port header'
1361017Szelenkov@nginx.com        )
137484Szelenkov@nginx.com
1381250Szelenkov@nginx.com    @unittest.skip('not yet')
1391250Szelenkov@nginx.com    def test_python_application_working_directory_invalid(self):
1401250Szelenkov@nginx.com        self.load('empty')
1411250Szelenkov@nginx.com
1421250Szelenkov@nginx.com        self.assertIn(
1431250Szelenkov@nginx.com            'success',
1441250Szelenkov@nginx.com            self.conf('"/blah"', 'applications/empty/working_directory'),
1451250Szelenkov@nginx.com            'configure invalid working_directory',
1461250Szelenkov@nginx.com        )
1471250Szelenkov@nginx.com
1481250Szelenkov@nginx.com        self.assertEqual(self.get()['status'], 500, 'status')
1491250Szelenkov@nginx.com
150496Szelenkov@nginx.com    def test_python_application_204_transfer_encoding(self):
151552Szelenkov@nginx.com        self.load('204_no_content')
152496Szelenkov@nginx.com
1531017Szelenkov@nginx.com        self.assertNotIn(
1541017Szelenkov@nginx.com            'Transfer-Encoding',
1551017Szelenkov@nginx.com            self.get()['headers'],
1561017Szelenkov@nginx.com            '204 header transfer encoding',
1571017Szelenkov@nginx.com        )
158484Szelenkov@nginx.com
159602Szelenkov@nginx.com    def test_python_application_ctx_iter_atexit(self):
160602Szelenkov@nginx.com        self.load('ctx_iter_atexit')
161602Szelenkov@nginx.com
1621017Szelenkov@nginx.com        resp = self.post(
1631017Szelenkov@nginx.com            headers={
1641017Szelenkov@nginx.com                'Host': 'localhost',
1651017Szelenkov@nginx.com                'Connection': 'close',
1661017Szelenkov@nginx.com                'Content-Type': 'text/html',
1671017Szelenkov@nginx.com            },
1681017Szelenkov@nginx.com            body='0123456789',
1691017Szelenkov@nginx.com        )
170602Szelenkov@nginx.com
171602Szelenkov@nginx.com        self.assertEqual(resp['status'], 200, 'ctx iter status')
172602Szelenkov@nginx.com        self.assertEqual(resp['body'], '0123456789', 'ctx iter body')
173602Szelenkov@nginx.com
1741017Szelenkov@nginx.com        self.conf({"listeners": {}, "applications": {}})
175602Szelenkov@nginx.com
176602Szelenkov@nginx.com        self.stop()
177602Szelenkov@nginx.com
1781017Szelenkov@nginx.com        self.assertIsNotNone(
1791028Szelenkov@nginx.com            self.wait_for_record(r'RuntimeError'), 'ctx iter atexit'
1801017Szelenkov@nginx.com        )
181602Szelenkov@nginx.com
182603Szelenkov@nginx.com    def test_python_keepalive_body(self):
183603Szelenkov@nginx.com        self.load('mirror')
184603Szelenkov@nginx.com
1851029Szelenkov@nginx.com        self.assertEqual(self.get()['status'], 200, 'init')
1861029Szelenkov@nginx.com
1871017Szelenkov@nginx.com        (resp, sock) = self.post(
1881017Szelenkov@nginx.com            headers={
1891017Szelenkov@nginx.com                'Host': 'localhost',
1901017Szelenkov@nginx.com                'Connection': 'keep-alive',
1911017Szelenkov@nginx.com                'Content-Type': 'text/html',
1921017Szelenkov@nginx.com            },
1931017Szelenkov@nginx.com            start=True,
1941017Szelenkov@nginx.com            body='0123456789' * 500,
1951029Szelenkov@nginx.com            read_timeout=1,
1961017Szelenkov@nginx.com        )
197603Szelenkov@nginx.com
198603Szelenkov@nginx.com        self.assertEqual(resp['body'], '0123456789' * 500, 'keep-alive 1')
199603Szelenkov@nginx.com
2001017Szelenkov@nginx.com        resp = self.post(
2011017Szelenkov@nginx.com            headers={
2021017Szelenkov@nginx.com                'Host': 'localhost',
2031017Szelenkov@nginx.com                'Connection': 'close',
2041017Szelenkov@nginx.com                'Content-Type': 'text/html',
2051017Szelenkov@nginx.com            },
2061017Szelenkov@nginx.com            sock=sock,
2071017Szelenkov@nginx.com            body='0123456789',
2081017Szelenkov@nginx.com        )
209603Szelenkov@nginx.com
210603Szelenkov@nginx.com        self.assertEqual(resp['body'], '0123456789', 'keep-alive 2')
211603Szelenkov@nginx.com
212684Szelenkov@nginx.com    def test_python_keepalive_reconfigure(self):
2131017Szelenkov@nginx.com        self.skip_alerts.extend(
2141017Szelenkov@nginx.com            [
2151017Szelenkov@nginx.com                r'pthread_mutex.+failed',
2161017Szelenkov@nginx.com                r'failed to apply',
2171017Szelenkov@nginx.com                r'process \d+ exited on signal',
2181017Szelenkov@nginx.com            ]
2191017Szelenkov@nginx.com        )
220684Szelenkov@nginx.com        self.load('mirror')
221684Szelenkov@nginx.com
2221029Szelenkov@nginx.com        self.assertEqual(self.get()['status'], 200, 'init')
2231029Szelenkov@nginx.com
224684Szelenkov@nginx.com        body = '0123456789'
225684Szelenkov@nginx.com        conns = 3
226684Szelenkov@nginx.com        socks = []
227684Szelenkov@nginx.com
228684Szelenkov@nginx.com        for i in range(conns):
2291017Szelenkov@nginx.com            (resp, sock) = self.post(
2301017Szelenkov@nginx.com                headers={
2311017Szelenkov@nginx.com                    'Host': 'localhost',
2321017Szelenkov@nginx.com                    'Connection': 'keep-alive',
2331017Szelenkov@nginx.com                    'Content-Type': 'text/html',
2341017Szelenkov@nginx.com                },
2351017Szelenkov@nginx.com                start=True,
2361017Szelenkov@nginx.com                body=body,
2371029Szelenkov@nginx.com                read_timeout=1,
2381017Szelenkov@nginx.com            )
239684Szelenkov@nginx.com
240684Szelenkov@nginx.com            self.assertEqual(resp['body'], body, 'keep-alive open')
2411017Szelenkov@nginx.com            self.assertIn(
2421017Szelenkov@nginx.com                'success',
2431026Szelenkov@nginx.com                self.conf(str(i + 1), 'applications/mirror/processes'),
2441017Szelenkov@nginx.com                'reconfigure',
2451017Szelenkov@nginx.com            )
246684Szelenkov@nginx.com
247684Szelenkov@nginx.com            socks.append(sock)
248684Szelenkov@nginx.com
249684Szelenkov@nginx.com        for i in range(conns):
2501017Szelenkov@nginx.com            (resp, sock) = self.post(
2511017Szelenkov@nginx.com                headers={
2521017Szelenkov@nginx.com                    'Host': 'localhost',
2531017Szelenkov@nginx.com                    'Connection': 'keep-alive',
2541017Szelenkov@nginx.com                    'Content-Type': 'text/html',
2551017Szelenkov@nginx.com                },
2561017Szelenkov@nginx.com                start=True,
2571017Szelenkov@nginx.com                sock=socks[i],
2581017Szelenkov@nginx.com                body=body,
2591029Szelenkov@nginx.com                read_timeout=1,
2601017Szelenkov@nginx.com            )
261684Szelenkov@nginx.com
262684Szelenkov@nginx.com            self.assertEqual(resp['body'], body, 'keep-alive request')
2631017Szelenkov@nginx.com            self.assertIn(
2641017Szelenkov@nginx.com                'success',
2651026Szelenkov@nginx.com                self.conf(str(i + 1), 'applications/mirror/processes'),
2661017Szelenkov@nginx.com                'reconfigure 2',
2671017Szelenkov@nginx.com            )
268684Szelenkov@nginx.com
269684Szelenkov@nginx.com        for i in range(conns):
2701017Szelenkov@nginx.com            resp = self.post(
2711017Szelenkov@nginx.com                headers={
2721017Szelenkov@nginx.com                    'Host': 'localhost',
2731017Szelenkov@nginx.com                    'Connection': 'close',
2741017Szelenkov@nginx.com                    'Content-Type': 'text/html',
2751017Szelenkov@nginx.com                },
2761017Szelenkov@nginx.com                sock=socks[i],
2771017Szelenkov@nginx.com                body=body,
2781017Szelenkov@nginx.com            )
279684Szelenkov@nginx.com
280684Szelenkov@nginx.com            self.assertEqual(resp['body'], body, 'keep-alive close')
2811017Szelenkov@nginx.com            self.assertIn(
2821017Szelenkov@nginx.com                'success',
2831026Szelenkov@nginx.com                self.conf(str(i + 1), 'applications/mirror/processes'),
2841017Szelenkov@nginx.com                'reconfigure 3',
2851017Szelenkov@nginx.com            )
286684Szelenkov@nginx.com
287750Szelenkov@nginx.com    def test_python_keepalive_reconfigure_2(self):
288750Szelenkov@nginx.com        self.load('mirror')
289750Szelenkov@nginx.com
2901029Szelenkov@nginx.com        self.assertEqual(self.get()['status'], 200, 'init')
2911029Szelenkov@nginx.com
292750Szelenkov@nginx.com        body = '0123456789'
293750Szelenkov@nginx.com
2941017Szelenkov@nginx.com        (resp, sock) = self.post(
2951017Szelenkov@nginx.com            headers={
2961017Szelenkov@nginx.com                'Host': 'localhost',
2971017Szelenkov@nginx.com                'Connection': 'keep-alive',
2981017Szelenkov@nginx.com                'Content-Type': 'text/html',
2991017Szelenkov@nginx.com            },
3001017Szelenkov@nginx.com            start=True,
3011017Szelenkov@nginx.com            body=body,
3021029Szelenkov@nginx.com            read_timeout=1,
3031017Szelenkov@nginx.com        )
304750Szelenkov@nginx.com
305750Szelenkov@nginx.com        self.assertEqual(resp['body'], body, 'reconfigure 2 keep-alive 1')
306750Szelenkov@nginx.com
307750Szelenkov@nginx.com        self.load('empty')
308750Szelenkov@nginx.com
3091029Szelenkov@nginx.com        self.assertEqual(self.get()['status'], 200, 'init')
3101029Szelenkov@nginx.com
3111017Szelenkov@nginx.com        (resp, sock) = self.post(
3121017Szelenkov@nginx.com            headers={
3131017Szelenkov@nginx.com                'Host': 'localhost',
3141017Szelenkov@nginx.com                'Connection': 'close',
3151017Szelenkov@nginx.com                'Content-Type': 'text/html',
3161017Szelenkov@nginx.com            },
3171017Szelenkov@nginx.com            start=True,
3181017Szelenkov@nginx.com            sock=sock,
3191017Szelenkov@nginx.com            body=body,
3201017Szelenkov@nginx.com        )
321750Szelenkov@nginx.com
322750Szelenkov@nginx.com        self.assertEqual(resp['status'], 200, 'reconfigure 2 keep-alive 2')
323750Szelenkov@nginx.com        self.assertEqual(resp['body'], '', 'reconfigure 2 keep-alive 2 body')
324750Szelenkov@nginx.com
3251017Szelenkov@nginx.com        self.assertIn(
3261017Szelenkov@nginx.com            'success',
3271017Szelenkov@nginx.com            self.conf({"listeners": {}, "applications": {}}),
3281017Szelenkov@nginx.com            'reconfigure 2 clear configuration',
3291017Szelenkov@nginx.com        )
330750Szelenkov@nginx.com
331750Szelenkov@nginx.com        resp = self.get(sock=sock)
332750Szelenkov@nginx.com
333750Szelenkov@nginx.com        self.assertEqual(resp, {}, 'reconfigure 2 keep-alive 3')
334750Szelenkov@nginx.com
335750Szelenkov@nginx.com    def test_python_keepalive_reconfigure_3(self):
336750Szelenkov@nginx.com        self.load('empty')
337750Szelenkov@nginx.com
3381029Szelenkov@nginx.com        self.assertEqual(self.get()['status'], 200, 'init')
3391029Szelenkov@nginx.com
3401017Szelenkov@nginx.com        (resp, sock) = self.http(
3411017Szelenkov@nginx.com            b"""GET / HTTP/1.1
3421017Szelenkov@nginx.com""",
3431017Szelenkov@nginx.com            start=True,
3441017Szelenkov@nginx.com            raw=True,
3451043Szelenkov@nginx.com            read_timeout=5,
3461017Szelenkov@nginx.com        )
347750Szelenkov@nginx.com
3481017Szelenkov@nginx.com        self.assertIn(
3491017Szelenkov@nginx.com            'success',
3501017Szelenkov@nginx.com            self.conf({"listeners": {}, "applications": {}}),
3511017Szelenkov@nginx.com            'reconfigure 3 clear configuration',
3521017Szelenkov@nginx.com        )
353750Szelenkov@nginx.com
3541017Szelenkov@nginx.com        resp = self.http(
3551017Szelenkov@nginx.com            b"""Host: localhost
356750Szelenkov@nginx.comConnection: close
357750Szelenkov@nginx.com
3581017Szelenkov@nginx.com""",
3591017Szelenkov@nginx.com            sock=sock,
3601017Szelenkov@nginx.com            raw=True,
3611017Szelenkov@nginx.com        )
362750Szelenkov@nginx.com
363750Szelenkov@nginx.com        self.assertEqual(resp['status'], 200, 'reconfigure 3')
364750Szelenkov@nginx.com
365603Szelenkov@nginx.com    def test_python_atexit(self):
366603Szelenkov@nginx.com        self.load('atexit')
367603Szelenkov@nginx.com
368603Szelenkov@nginx.com        self.get()
369603Szelenkov@nginx.com
3701017Szelenkov@nginx.com        self.conf({"listeners": {}, "applications": {}})
371603Szelenkov@nginx.com
372603Szelenkov@nginx.com        self.stop()
373603Szelenkov@nginx.com
3741028Szelenkov@nginx.com        self.assertIsNotNone(
3751028Szelenkov@nginx.com            self.wait_for_record(r'At exit called\.'), 'atexit'
3761028Szelenkov@nginx.com        )
377603Szelenkov@nginx.com
3781064Szelenkov@nginx.com    @unittest.skip('not yet')
379603Szelenkov@nginx.com    def test_python_application_start_response_exit(self):
380603Szelenkov@nginx.com        self.load('start_response_exit')
381603Szelenkov@nginx.com
382603Szelenkov@nginx.com        self.assertEqual(self.get()['status'], 500, 'start response exit')
383603Szelenkov@nginx.com
3841064Szelenkov@nginx.com    @unittest.skip('not yet')
385603Szelenkov@nginx.com    def test_python_application_input_iter(self):
386603Szelenkov@nginx.com        self.load('input_iter')
387603Szelenkov@nginx.com
388603Szelenkov@nginx.com        body = '0123456789'
389603Szelenkov@nginx.com
390603Szelenkov@nginx.com        self.assertEqual(self.post(body=body)['body'], body, 'input iter')
391603Szelenkov@nginx.com
392603Szelenkov@nginx.com    def test_python_application_input_read_length(self):
393603Szelenkov@nginx.com        self.load('input_read_length')
394603Szelenkov@nginx.com
395603Szelenkov@nginx.com        body = '0123456789'
396603Szelenkov@nginx.com
3971017Szelenkov@nginx.com        resp = self.post(
3981017Szelenkov@nginx.com            headers={
3991017Szelenkov@nginx.com                'Host': 'localhost',
4001017Szelenkov@nginx.com                'Input-Length': '5',
4011017Szelenkov@nginx.com                'Connection': 'close',
4021017Szelenkov@nginx.com            },
4031017Szelenkov@nginx.com            body=body,
4041017Szelenkov@nginx.com        )
405603Szelenkov@nginx.com
406603Szelenkov@nginx.com        self.assertEqual(resp['body'], body[:5], 'input read length lt body')
407603Szelenkov@nginx.com
4081017Szelenkov@nginx.com        resp = self.post(
4091017Szelenkov@nginx.com            headers={
4101017Szelenkov@nginx.com                'Host': 'localhost',
4111017Szelenkov@nginx.com                'Input-Length': '15',
4121017Szelenkov@nginx.com                'Connection': 'close',
4131017Szelenkov@nginx.com            },
4141017Szelenkov@nginx.com            body=body,
4151017Szelenkov@nginx.com        )
416603Szelenkov@nginx.com
417603Szelenkov@nginx.com        self.assertEqual(resp['body'], body, 'input read length gt body')
418603Szelenkov@nginx.com
4191017Szelenkov@nginx.com        resp = self.post(
4201017Szelenkov@nginx.com            headers={
4211017Szelenkov@nginx.com                'Host': 'localhost',
4221017Szelenkov@nginx.com                'Input-Length': '0',
4231017Szelenkov@nginx.com                'Connection': 'close',
4241017Szelenkov@nginx.com            },
4251017Szelenkov@nginx.com            body=body,
4261017Szelenkov@nginx.com        )
427603Szelenkov@nginx.com
428603Szelenkov@nginx.com        self.assertEqual(resp['body'], '', 'input read length zero')
429603Szelenkov@nginx.com
4301017Szelenkov@nginx.com        resp = self.post(
4311017Szelenkov@nginx.com            headers={
4321017Szelenkov@nginx.com                'Host': 'localhost',
4331017Szelenkov@nginx.com                'Input-Length': '-1',
4341017Szelenkov@nginx.com                'Connection': 'close',
4351017Szelenkov@nginx.com            },
4361017Szelenkov@nginx.com            body=body,
4371017Szelenkov@nginx.com        )
438603Szelenkov@nginx.com
439603Szelenkov@nginx.com        self.assertEqual(resp['body'], body, 'input read length negative')
440603Szelenkov@nginx.com
4411064Szelenkov@nginx.com    @unittest.skip('not yet')
442603Szelenkov@nginx.com    def test_python_application_errors_write(self):
443603Szelenkov@nginx.com        self.load('errors_write')
444603Szelenkov@nginx.com
445603Szelenkov@nginx.com        self.get()
446603Szelenkov@nginx.com
447603Szelenkov@nginx.com        self.stop()
448603Szelenkov@nginx.com
449603Szelenkov@nginx.com        self.assertIsNotNone(
4501028Szelenkov@nginx.com            self.wait_for_record(r'\[error\].+Error in application\.'),
4511017Szelenkov@nginx.com            'errors write',
4521017Szelenkov@nginx.com        )
453603Szelenkov@nginx.com
454603Szelenkov@nginx.com    def test_python_application_body_array(self):
455603Szelenkov@nginx.com        self.load('body_array')
456603Szelenkov@nginx.com
457603Szelenkov@nginx.com        self.assertEqual(self.get()['body'], '0123456789', 'body array')
458603Szelenkov@nginx.com
459603Szelenkov@nginx.com    def test_python_application_body_io(self):
460603Szelenkov@nginx.com        self.load('body_io')
461603Szelenkov@nginx.com
462603Szelenkov@nginx.com        self.assertEqual(self.get()['body'], '0123456789', 'body io')
463603Szelenkov@nginx.com
464603Szelenkov@nginx.com    def test_python_application_body_io_file(self):
465603Szelenkov@nginx.com        self.load('body_io_file')
466603Szelenkov@nginx.com
467603Szelenkov@nginx.com        self.assertEqual(self.get()['body'], 'body\n', 'body io file')
468603Szelenkov@nginx.com
4691064Szelenkov@nginx.com    @unittest.skip('not yet')
470603Szelenkov@nginx.com    def test_python_application_syntax_error(self):
471603Szelenkov@nginx.com        self.skip_alerts.append(r'Python failed to import module "wsgi"')
472603Szelenkov@nginx.com        self.load('syntax_error')
473603Szelenkov@nginx.com
474603Szelenkov@nginx.com        self.assertEqual(self.get()['status'], 500, 'syntax error')
475603Szelenkov@nginx.com
476603Szelenkov@nginx.com    def test_python_application_close(self):
477603Szelenkov@nginx.com        self.load('close')
478603Szelenkov@nginx.com
479603Szelenkov@nginx.com        self.get()
480603Szelenkov@nginx.com
481603Szelenkov@nginx.com        self.stop()
482603Szelenkov@nginx.com
4831028Szelenkov@nginx.com        self.assertIsNotNone(self.wait_for_record(r'Close called\.'), 'close')
484603Szelenkov@nginx.com
485603Szelenkov@nginx.com    def test_python_application_close_error(self):
486603Szelenkov@nginx.com        self.load('close_error')
487603Szelenkov@nginx.com
488603Szelenkov@nginx.com        self.get()
489603Szelenkov@nginx.com
490603Szelenkov@nginx.com        self.stop()
491603Szelenkov@nginx.com
4921017Szelenkov@nginx.com        self.assertIsNotNone(
4931028Szelenkov@nginx.com            self.wait_for_record(r'Close called\.'), 'close error'
4941017Szelenkov@nginx.com        )
495603Szelenkov@nginx.com
496617Szelenkov@nginx.com    def test_python_application_not_iterable(self):
497617Szelenkov@nginx.com        self.load('not_iterable')
498617Szelenkov@nginx.com
499665Szelenkov@nginx.com        self.get()
500617Szelenkov@nginx.com
501617Szelenkov@nginx.com        self.stop()
502617Szelenkov@nginx.com
5031017Szelenkov@nginx.com        self.assertIsNotNone(
5041028Szelenkov@nginx.com            self.wait_for_record(
5051017Szelenkov@nginx.com                r'\[error\].+the application returned not an iterable object'
5061017Szelenkov@nginx.com            ),
5071017Szelenkov@nginx.com            'not iterable',
5081017Szelenkov@nginx.com        )
509617Szelenkov@nginx.com
510664Szelenkov@nginx.com    def test_python_application_write(self):
511664Szelenkov@nginx.com        self.load('write')
512664Szelenkov@nginx.com
513664Szelenkov@nginx.com        self.assertEqual(self.get()['body'], '0123456789', 'write')
514664Szelenkov@nginx.com
5151261Szelenkov@nginx.com    def test_python_application_threading(self):
5161261Szelenkov@nginx.com        """wait_for_record() timeouts after 5s while every thread works at
5171261Szelenkov@nginx.com        least 3s.  So without releasing GIL test should fail.
5181261Szelenkov@nginx.com        """
5191261Szelenkov@nginx.com
5201261Szelenkov@nginx.com        self.load('threading')
5211261Szelenkov@nginx.com
5221261Szelenkov@nginx.com        for _ in range(10):
5231261Szelenkov@nginx.com            self.get(no_recv=True)
5241261Szelenkov@nginx.com
5251261Szelenkov@nginx.com        self.assertIsNotNone(
5261261Szelenkov@nginx.com            self.wait_for_record(r'\(5\) Thread: 100'), 'last thread finished'
5271261Szelenkov@nginx.com        )
5281017Szelenkov@nginx.com
529*1283Szelenkov@nginx.com    def test_python_application_iter_exception(self):
530*1283Szelenkov@nginx.com        self.load('iter_exception')
531*1283Szelenkov@nginx.com
532*1283Szelenkov@nginx.com        # Default request doesn't lead to the exception.
533*1283Szelenkov@nginx.com
534*1283Szelenkov@nginx.com        resp = self.get(
535*1283Szelenkov@nginx.com            headers={
536*1283Szelenkov@nginx.com                'Host': 'localhost',
537*1283Szelenkov@nginx.com                'X-Skip': '9',
538*1283Szelenkov@nginx.com                'X-Chunked': '1',
539*1283Szelenkov@nginx.com                'Connection': 'close',
540*1283Szelenkov@nginx.com            }
541*1283Szelenkov@nginx.com        )
542*1283Szelenkov@nginx.com        self.assertEqual(resp['status'], 200, 'status')
543*1283Szelenkov@nginx.com        self.assertEqual(resp['body'][-5:], '0\r\n\r\n', 'body')
544*1283Szelenkov@nginx.com
545*1283Szelenkov@nginx.com        # Exception before start_response().
546*1283Szelenkov@nginx.com
547*1283Szelenkov@nginx.com        self.assertEqual(self.get()['status'], 503, 'error')
548*1283Szelenkov@nginx.com
549*1283Szelenkov@nginx.com        self.assertIsNotNone(self.wait_for_record(r'Traceback'), 'traceback')
550*1283Szelenkov@nginx.com        self.assertIsNotNone(
551*1283Szelenkov@nginx.com            self.wait_for_record(r'raise Exception\(\'first exception\'\)'),
552*1283Szelenkov@nginx.com            'first exception raise',
553*1283Szelenkov@nginx.com        )
554*1283Szelenkov@nginx.com        self.assertEqual(
555*1283Szelenkov@nginx.com            len(self.findall(r'Traceback')), 1, 'traceback count 1'
556*1283Szelenkov@nginx.com        )
557*1283Szelenkov@nginx.com
558*1283Szelenkov@nginx.com        # Exception after start_response(), before first write().
559*1283Szelenkov@nginx.com
560*1283Szelenkov@nginx.com        self.assertEqual(
561*1283Szelenkov@nginx.com            self.get(
562*1283Szelenkov@nginx.com                headers={
563*1283Szelenkov@nginx.com                    'Host': 'localhost',
564*1283Szelenkov@nginx.com                    'X-Skip': '1',
565*1283Szelenkov@nginx.com                    'Connection': 'close',
566*1283Szelenkov@nginx.com                }
567*1283Szelenkov@nginx.com            )['status'],
568*1283Szelenkov@nginx.com            503,
569*1283Szelenkov@nginx.com            'error 2',
570*1283Szelenkov@nginx.com        )
571*1283Szelenkov@nginx.com
572*1283Szelenkov@nginx.com        self.assertIsNotNone(
573*1283Szelenkov@nginx.com            self.wait_for_record(r'raise Exception\(\'second exception\'\)'),
574*1283Szelenkov@nginx.com            'exception raise second',
575*1283Szelenkov@nginx.com        )
576*1283Szelenkov@nginx.com        self.assertEqual(
577*1283Szelenkov@nginx.com            len(self.findall(r'Traceback')), 2, 'traceback count 2'
578*1283Szelenkov@nginx.com        )
579*1283Szelenkov@nginx.com
580*1283Szelenkov@nginx.com        # Exception after first write(), before first __next__().
581*1283Szelenkov@nginx.com
582*1283Szelenkov@nginx.com        _, sock = self.get(
583*1283Szelenkov@nginx.com            headers={
584*1283Szelenkov@nginx.com                'Host': 'localhost',
585*1283Szelenkov@nginx.com                'X-Skip': '2',
586*1283Szelenkov@nginx.com                'Connection': 'keep-alive',
587*1283Szelenkov@nginx.com            },
588*1283Szelenkov@nginx.com            start=True,
589*1283Szelenkov@nginx.com        )
590*1283Szelenkov@nginx.com
591*1283Szelenkov@nginx.com        self.assertIsNotNone(
592*1283Szelenkov@nginx.com            self.wait_for_record(r'raise Exception\(\'third exception\'\)'),
593*1283Szelenkov@nginx.com            'exception raise third',
594*1283Szelenkov@nginx.com        )
595*1283Szelenkov@nginx.com        self.assertEqual(
596*1283Szelenkov@nginx.com            len(self.findall(r'Traceback')), 3, 'traceback count 3'
597*1283Szelenkov@nginx.com        )
598*1283Szelenkov@nginx.com
599*1283Szelenkov@nginx.com        self.assertDictEqual(self.get(sock=sock), {}, 'closed connection')
600*1283Szelenkov@nginx.com
601*1283Szelenkov@nginx.com        # Exception after first write(), before first __next__(),
602*1283Szelenkov@nginx.com        # chunked (incomplete body).
603*1283Szelenkov@nginx.com
604*1283Szelenkov@nginx.com        resp = self.get(
605*1283Szelenkov@nginx.com            headers={
606*1283Szelenkov@nginx.com                'Host': 'localhost',
607*1283Szelenkov@nginx.com                'X-Skip': '2',
608*1283Szelenkov@nginx.com                'X-Chunked': '1',
609*1283Szelenkov@nginx.com                'Connection': 'close',
610*1283Szelenkov@nginx.com            }
611*1283Szelenkov@nginx.com        )
612*1283Szelenkov@nginx.com        if 'body' in resp:
613*1283Szelenkov@nginx.com            self.assertNotEqual(
614*1283Szelenkov@nginx.com                resp['body'][-5:], '0\r\n\r\n', 'incomplete body'
615*1283Szelenkov@nginx.com            )
616*1283Szelenkov@nginx.com        self.assertEqual(
617*1283Szelenkov@nginx.com            len(self.findall(r'Traceback')), 4, 'traceback count 4'
618*1283Szelenkov@nginx.com        )
619*1283Szelenkov@nginx.com
620*1283Szelenkov@nginx.com        # Exception in __next__().
621*1283Szelenkov@nginx.com
622*1283Szelenkov@nginx.com        _, sock = self.get(
623*1283Szelenkov@nginx.com            headers={
624*1283Szelenkov@nginx.com                'Host': 'localhost',
625*1283Szelenkov@nginx.com                'X-Skip': '3',
626*1283Szelenkov@nginx.com                'Connection': 'keep-alive',
627*1283Szelenkov@nginx.com            },
628*1283Szelenkov@nginx.com            start=True,
629*1283Szelenkov@nginx.com        )
630*1283Szelenkov@nginx.com
631*1283Szelenkov@nginx.com        self.assertIsNotNone(
632*1283Szelenkov@nginx.com            self.wait_for_record(r'raise Exception\(\'next exception\'\)'),
633*1283Szelenkov@nginx.com            'exception raise next',
634*1283Szelenkov@nginx.com        )
635*1283Szelenkov@nginx.com        self.assertEqual(
636*1283Szelenkov@nginx.com            len(self.findall(r'Traceback')), 5, 'traceback count 5'
637*1283Szelenkov@nginx.com        )
638*1283Szelenkov@nginx.com
639*1283Szelenkov@nginx.com        self.assertDictEqual(self.get(sock=sock), {}, 'closed connection 2')
640*1283Szelenkov@nginx.com
641*1283Szelenkov@nginx.com        # Exception in __next__(), chunked (incomplete body).
642*1283Szelenkov@nginx.com
643*1283Szelenkov@nginx.com        resp = self.get(
644*1283Szelenkov@nginx.com            headers={
645*1283Szelenkov@nginx.com                'Host': 'localhost',
646*1283Szelenkov@nginx.com                'X-Skip': '3',
647*1283Szelenkov@nginx.com                'X-Chunked': '1',
648*1283Szelenkov@nginx.com                'Connection': 'close',
649*1283Szelenkov@nginx.com            }
650*1283Szelenkov@nginx.com        )
651*1283Szelenkov@nginx.com        if 'body' in resp:
652*1283Szelenkov@nginx.com            self.assertNotEqual(
653*1283Szelenkov@nginx.com                resp['body'][-5:], '0\r\n\r\n', 'incomplete body 2'
654*1283Szelenkov@nginx.com            )
655*1283Szelenkov@nginx.com        self.assertEqual(
656*1283Szelenkov@nginx.com            len(self.findall(r'Traceback')), 6, 'traceback count 6'
657*1283Szelenkov@nginx.com        )
658*1283Szelenkov@nginx.com
659*1283Szelenkov@nginx.com        # Exception before start_response() and in close().
660*1283Szelenkov@nginx.com
661*1283Szelenkov@nginx.com        self.assertEqual(
662*1283Szelenkov@nginx.com            self.get(
663*1283Szelenkov@nginx.com                headers={
664*1283Szelenkov@nginx.com                    'Host': 'localhost',
665*1283Szelenkov@nginx.com                    'X-Not-Skip-Close': '1',
666*1283Szelenkov@nginx.com                    'Connection': 'close',
667*1283Szelenkov@nginx.com                }
668*1283Szelenkov@nginx.com            )['status'],
669*1283Szelenkov@nginx.com            503,
670*1283Szelenkov@nginx.com            'error',
671*1283Szelenkov@nginx.com        )
672*1283Szelenkov@nginx.com
673*1283Szelenkov@nginx.com        self.assertIsNotNone(
674*1283Szelenkov@nginx.com            self.wait_for_record(r'raise Exception\(\'close exception\'\)'),
675*1283Szelenkov@nginx.com            'exception raise close',
676*1283Szelenkov@nginx.com        )
677*1283Szelenkov@nginx.com        self.assertEqual(
678*1283Szelenkov@nginx.com            len(self.findall(r'Traceback')), 8, 'traceback count 8'
679*1283Szelenkov@nginx.com        )
680*1283Szelenkov@nginx.com
681484Szelenkov@nginx.comif __name__ == '__main__':
6821019Szelenkov@nginx.com    TestPythonApplication.main()
683