1*899Szelenkov@nginx.comimport time
2484Szelenkov@nginx.comimport unittest
3484Szelenkov@nginx.comimport unit
4484Szelenkov@nginx.com
5552Szelenkov@nginx.comclass TestUnitPythonApplication(unit.TestUnitApplicationPython):
6484Szelenkov@nginx.com
7484Szelenkov@nginx.com    def setUpClass():
8550Szelenkov@nginx.com        unit.TestUnit().check_modules('python')
9484Szelenkov@nginx.com
10552Szelenkov@nginx.com    def test_python_application_variables(self):
11552Szelenkov@nginx.com        self.load('variables')
12484Szelenkov@nginx.com
13484Szelenkov@nginx.com        body = 'Test body string.'
14484Szelenkov@nginx.com
15505Szelenkov@nginx.com        resp = self.post(headers={
16484Szelenkov@nginx.com            'Host': 'localhost',
17484Szelenkov@nginx.com            'Content-Type': 'text/html',
18484Szelenkov@nginx.com            'Custom-Header': 'blah'
19505Szelenkov@nginx.com        }, body=body)
20484Szelenkov@nginx.com
21505Szelenkov@nginx.com        self.assertEqual(resp['status'], 200, 'status')
22505Szelenkov@nginx.com        headers = resp['headers']
23674Szelenkov@nginx.com        header_server = headers.pop('Server')
24674Szelenkov@nginx.com        self.assertRegex(header_server, r'Unit/[\d\.]+', 'server header')
25674Szelenkov@nginx.com        self.assertEqual(headers.pop('Server-Software'), header_server,
26674Szelenkov@nginx.com            'server software header')
27599Szelenkov@nginx.com
28599Szelenkov@nginx.com        date = headers.pop('Date')
29599Szelenkov@nginx.com        self.assertEqual(date[-4:], ' GMT', 'date header timezone')
30599Szelenkov@nginx.com        self.assertLess(abs(self.date_to_sec_epoch(date) - self.sec_epoch()), 5,
31599Szelenkov@nginx.com            'date header')
32599Szelenkov@nginx.com
33495Szelenkov@nginx.com        self.assertDictEqual(headers, {
34495Szelenkov@nginx.com            'Content-Length': str(len(body)),
35495Szelenkov@nginx.com            'Content-Type': 'text/html',
36495Szelenkov@nginx.com            'Request-Method': 'POST',
37495Szelenkov@nginx.com            'Request-Uri': '/',
38495Szelenkov@nginx.com            'Http-Host': 'localhost',
39495Szelenkov@nginx.com            'Server-Protocol': 'HTTP/1.1',
40603Szelenkov@nginx.com            'Custom-Header': 'blah',
41603Szelenkov@nginx.com            'Wsgi-Version': '(1, 0)',
42603Szelenkov@nginx.com            'Wsgi-Url-Scheme': 'http',
43603Szelenkov@nginx.com            'Wsgi-Multithread': 'False',
44603Szelenkov@nginx.com            'Wsgi-Multiprocess': 'True',
45603Szelenkov@nginx.com            'Wsgi-Run-Once': 'False'
46495Szelenkov@nginx.com        }, 'headers')
47505Szelenkov@nginx.com        self.assertEqual(resp['body'], body, 'body')
48484Szelenkov@nginx.com
49497Szelenkov@nginx.com    def test_python_application_query_string(self):
50552Szelenkov@nginx.com        self.load('query_string')
51497Szelenkov@nginx.com
52505Szelenkov@nginx.com        resp = self.get(url='/?var1=val1&var2=val2')
53497Szelenkov@nginx.com
54513Szelenkov@nginx.com        self.assertEqual(resp['headers']['Query-String'], 'var1=val1&var2=val2',
55513Szelenkov@nginx.com            'Query-String header')
56497Szelenkov@nginx.com
57894Szelenkov@nginx.com    def test_python_application_query_string_empty(self):
58894Szelenkov@nginx.com        self.load('query_string')
59894Szelenkov@nginx.com
60894Szelenkov@nginx.com        resp = self.get(url='/?')
61894Szelenkov@nginx.com
62894Szelenkov@nginx.com        self.assertEqual(resp['status'], 200, 'query string empty status')
63894Szelenkov@nginx.com        self.assertEqual(resp['headers']['Query-String'], '',
64894Szelenkov@nginx.com            'query string empty')
65894Szelenkov@nginx.com
66894Szelenkov@nginx.com    @unittest.expectedFailure
67894Szelenkov@nginx.com    def test_python_application_query_string_absent(self):
68894Szelenkov@nginx.com        self.load('query_string')
69894Szelenkov@nginx.com
70894Szelenkov@nginx.com        resp = self.get()
71894Szelenkov@nginx.com
72894Szelenkov@nginx.com        self.assertEqual(resp['status'], 200, 'query string absent status')
73894Szelenkov@nginx.com        self.assertEqual(resp['headers']['Query-String'], '',
74894Szelenkov@nginx.com            'query string absent')
75894Szelenkov@nginx.com
76495Szelenkov@nginx.com    @unittest.expectedFailure
77495Szelenkov@nginx.com    def test_python_application_server_port(self):
78552Szelenkov@nginx.com        self.load('server_port')
79495Szelenkov@nginx.com
80505Szelenkov@nginx.com        self.assertEqual(self.get()['headers']['Server-Port'], '7080',
81495Szelenkov@nginx.com            'Server-Port header')
82484Szelenkov@nginx.com
83496Szelenkov@nginx.com    def test_python_application_204_transfer_encoding(self):
84552Szelenkov@nginx.com        self.load('204_no_content')
85496Szelenkov@nginx.com
86505Szelenkov@nginx.com        self.assertNotIn('Transfer-Encoding', self.get()['headers'],
87496Szelenkov@nginx.com            '204 header transfer encoding')
88484Szelenkov@nginx.com
89602Szelenkov@nginx.com    def test_python_application_ctx_iter_atexit(self):
90602Szelenkov@nginx.com        self.skip_alerts.append(r'sendmsg.+failed')
91602Szelenkov@nginx.com        self.load('ctx_iter_atexit')
92602Szelenkov@nginx.com
93602Szelenkov@nginx.com        resp = self.post(headers={
94602Szelenkov@nginx.com            'Connection': 'close',
95602Szelenkov@nginx.com            'Content-Type': 'text/html',
96602Szelenkov@nginx.com            'Host': 'localhost'
97602Szelenkov@nginx.com        }, body='0123456789')
98602Szelenkov@nginx.com
99602Szelenkov@nginx.com        self.assertEqual(resp['status'], 200, 'ctx iter status')
100602Szelenkov@nginx.com        self.assertEqual(resp['body'], '0123456789', 'ctx iter body')
101602Szelenkov@nginx.com
102602Szelenkov@nginx.com        self.conf({
103602Szelenkov@nginx.com            "listeners": {},
104602Szelenkov@nginx.com            "applications": {}
105602Szelenkov@nginx.com        })
106602Szelenkov@nginx.com
107602Szelenkov@nginx.com        self.stop()
108602Szelenkov@nginx.com
109*899Szelenkov@nginx.com        time.sleep(0.2)
110*899Szelenkov@nginx.com
111602Szelenkov@nginx.com        self.assertIsNotNone(self.search_in_log(r'RuntimeError'),
112602Szelenkov@nginx.com            'ctx iter atexit')
113602Szelenkov@nginx.com
114603Szelenkov@nginx.com    def test_python_keepalive_body(self):
115603Szelenkov@nginx.com        self.load('mirror')
116603Szelenkov@nginx.com
117603Szelenkov@nginx.com        (resp, sock) = self.post(headers={
118603Szelenkov@nginx.com            'Connection': 'keep-alive',
119603Szelenkov@nginx.com            'Content-Type': 'text/html',
120603Szelenkov@nginx.com            'Host': 'localhost'
121603Szelenkov@nginx.com        }, start=True, body='0123456789' * 500)
122603Szelenkov@nginx.com
123603Szelenkov@nginx.com        self.assertEqual(resp['body'], '0123456789' * 500, 'keep-alive 1')
124603Szelenkov@nginx.com
125603Szelenkov@nginx.com        resp = self.post(headers={
126603Szelenkov@nginx.com            'Connection': 'close',
127603Szelenkov@nginx.com            'Content-Type': 'text/html',
128603Szelenkov@nginx.com            'Host': 'localhost'
129603Szelenkov@nginx.com        }, sock=sock, body='0123456789')
130603Szelenkov@nginx.com
131603Szelenkov@nginx.com        self.assertEqual(resp['body'], '0123456789', 'keep-alive 2')
132603Szelenkov@nginx.com
133684Szelenkov@nginx.com    def test_python_keepalive_reconfigure(self):
134684Szelenkov@nginx.com        self.skip_alerts.extend([
135684Szelenkov@nginx.com            r'sendmsg.+failed',
136684Szelenkov@nginx.com            r'recvmsg.+failed'
137684Szelenkov@nginx.com        ])
138684Szelenkov@nginx.com        self.load('mirror')
139684Szelenkov@nginx.com
140684Szelenkov@nginx.com        body = '0123456789'
141684Szelenkov@nginx.com        conns = 3
142684Szelenkov@nginx.com        socks = []
143684Szelenkov@nginx.com
144684Szelenkov@nginx.com        for i in range(conns):
145684Szelenkov@nginx.com            (resp, sock) = self.post(headers={
146684Szelenkov@nginx.com                'Connection': 'keep-alive',
147684Szelenkov@nginx.com                'Content-Type': 'text/html',
148684Szelenkov@nginx.com                'Host': 'localhost'
149684Szelenkov@nginx.com            }, start=True, body=body)
150684Szelenkov@nginx.com
151684Szelenkov@nginx.com            self.assertEqual(resp['body'], body, 'keep-alive open')
152684Szelenkov@nginx.com            self.assertIn('success', self.conf({
153684Szelenkov@nginx.com                "spare": i % 4,
154684Szelenkov@nginx.com                "max": (i % 4) + 1
155760Szelenkov@nginx.com            }, 'applications/mirror/processes'), 'reconfigure')
156684Szelenkov@nginx.com
157684Szelenkov@nginx.com            socks.append(sock)
158684Szelenkov@nginx.com
159684Szelenkov@nginx.com        for i in range(conns):
160684Szelenkov@nginx.com            (resp, sock) = self.post(headers={
161684Szelenkov@nginx.com                'Connection': 'keep-alive',
162684Szelenkov@nginx.com                'Content-Type': 'text/html',
163684Szelenkov@nginx.com                'Host': 'localhost'
164684Szelenkov@nginx.com            }, start=True, sock=socks[i], body=body)
165684Szelenkov@nginx.com
166684Szelenkov@nginx.com            self.assertEqual(resp['body'], body, 'keep-alive request')
167684Szelenkov@nginx.com            self.assertIn('success', self.conf({
168684Szelenkov@nginx.com                "spare": i % 4,
169684Szelenkov@nginx.com                "max": (i % 4) + 1
170760Szelenkov@nginx.com            }, 'applications/mirror/processes'), 'reconfigure 2')
171684Szelenkov@nginx.com
172684Szelenkov@nginx.com        for i in range(conns):
173684Szelenkov@nginx.com            resp = self.post(headers={
174684Szelenkov@nginx.com                'Connection': 'close',
175684Szelenkov@nginx.com                'Content-Type': 'text/html',
176684Szelenkov@nginx.com                'Host': 'localhost'
177684Szelenkov@nginx.com            }, sock=socks[i], body=body)
178684Szelenkov@nginx.com
179684Szelenkov@nginx.com            self.assertEqual(resp['body'], body, 'keep-alive close')
180684Szelenkov@nginx.com            self.assertIn('success', self.conf({
181684Szelenkov@nginx.com                "spare": i % 4,
182684Szelenkov@nginx.com                "max": (i % 4) + 1
183760Szelenkov@nginx.com            }, 'applications/mirror/processes'), 'reconfigure 3')
184684Szelenkov@nginx.com
185750Szelenkov@nginx.com    def test_python_keepalive_reconfigure_2(self):
186750Szelenkov@nginx.com        self.skip_alerts.append(r'sendmsg.+failed')
187750Szelenkov@nginx.com        self.load('mirror')
188750Szelenkov@nginx.com
189750Szelenkov@nginx.com        body = '0123456789'
190750Szelenkov@nginx.com
191750Szelenkov@nginx.com        (resp, sock) = self.post(headers={
192750Szelenkov@nginx.com            'Connection': 'keep-alive',
193750Szelenkov@nginx.com            'Content-Type': 'text/html',
194750Szelenkov@nginx.com            'Host': 'localhost'
195750Szelenkov@nginx.com        }, start=True, body=body)
196750Szelenkov@nginx.com
197750Szelenkov@nginx.com        self.assertEqual(resp['body'], body, 'reconfigure 2 keep-alive 1')
198750Szelenkov@nginx.com
199750Szelenkov@nginx.com        self.load('empty')
200750Szelenkov@nginx.com
201750Szelenkov@nginx.com        (resp, sock) = self.post(headers={
202750Szelenkov@nginx.com            'Connection': 'close',
203750Szelenkov@nginx.com            'Content-Type': 'text/html',
204750Szelenkov@nginx.com            'Host': 'localhost'
205750Szelenkov@nginx.com        }, start=True, sock=sock, body=body)
206750Szelenkov@nginx.com
207750Szelenkov@nginx.com        self.assertEqual(resp['status'], 200, 'reconfigure 2 keep-alive 2')
208750Szelenkov@nginx.com        self.assertEqual(resp['body'], '', 'reconfigure 2 keep-alive 2 body')
209750Szelenkov@nginx.com
210750Szelenkov@nginx.com        self.assertIn('success', self.conf({
211750Szelenkov@nginx.com            "listeners": {},
212750Szelenkov@nginx.com            "applications": {}
213750Szelenkov@nginx.com        }), 'reconfigure 2 clear configuration')
214750Szelenkov@nginx.com
215750Szelenkov@nginx.com        resp = self.get(sock=sock)
216750Szelenkov@nginx.com
217750Szelenkov@nginx.com        self.assertEqual(resp, {}, 'reconfigure 2 keep-alive 3')
218750Szelenkov@nginx.com
219750Szelenkov@nginx.com    def test_python_keepalive_reconfigure_3(self):
220753Smax.romanov@nginx.com        self.skip_alerts.append(r'sendmsg.+failed')
221750Szelenkov@nginx.com        self.load('empty')
222750Szelenkov@nginx.com
223750Szelenkov@nginx.com        (resp, sock) = self.http(b"""GET / HTTP/1.1
224750Szelenkov@nginx.com""", start=True, raw=True)
225750Szelenkov@nginx.com
226750Szelenkov@nginx.com        self.assertIn('success', self.conf({
227750Szelenkov@nginx.com            "listeners": {},
228750Szelenkov@nginx.com            "applications": {}
229750Szelenkov@nginx.com        }), 'reconfigure 3 clear configuration')
230750Szelenkov@nginx.com
231750Szelenkov@nginx.com        resp = self.http(b"""Host: localhost
232750Szelenkov@nginx.comConnection: close
233750Szelenkov@nginx.com
234750Szelenkov@nginx.com""", sock=sock, raw=True)
235750Szelenkov@nginx.com
236750Szelenkov@nginx.com        self.assertEqual(resp['status'], 200, 'reconfigure 3')
237750Szelenkov@nginx.com
238603Szelenkov@nginx.com    def test_python_atexit(self):
239603Szelenkov@nginx.com        self.skip_alerts.append(r'sendmsg.+failed')
240603Szelenkov@nginx.com        self.load('atexit')
241603Szelenkov@nginx.com
242603Szelenkov@nginx.com        self.get()
243603Szelenkov@nginx.com
244603Szelenkov@nginx.com        self.conf({
245603Szelenkov@nginx.com            "listeners": {},
246603Szelenkov@nginx.com            "applications": {}
247603Szelenkov@nginx.com        })
248603Szelenkov@nginx.com
249603Szelenkov@nginx.com        self.stop()
250603Szelenkov@nginx.com
251603Szelenkov@nginx.com        self.assertIsNotNone(self.search_in_log(r'At exit called\.'), 'atexit')
252603Szelenkov@nginx.com
253603Szelenkov@nginx.com    @unittest.expectedFailure
254603Szelenkov@nginx.com    def test_python_application_start_response_exit(self):
255603Szelenkov@nginx.com        self.load('start_response_exit')
256603Szelenkov@nginx.com
257603Szelenkov@nginx.com        self.assertEqual(self.get()['status'], 500, 'start response exit')
258603Szelenkov@nginx.com
259603Szelenkov@nginx.com    @unittest.expectedFailure
260603Szelenkov@nginx.com    def test_python_application_input_iter(self):
261603Szelenkov@nginx.com        self.load('input_iter')
262603Szelenkov@nginx.com
263603Szelenkov@nginx.com        body = '0123456789'
264603Szelenkov@nginx.com
265603Szelenkov@nginx.com        self.assertEqual(self.post(body=body)['body'], body, 'input iter')
266603Szelenkov@nginx.com
267603Szelenkov@nginx.com    def test_python_application_input_read_length(self):
268603Szelenkov@nginx.com        self.load('input_read_length')
269603Szelenkov@nginx.com
270603Szelenkov@nginx.com        body = '0123456789'
271603Szelenkov@nginx.com
272603Szelenkov@nginx.com        resp = self.post(headers={
273603Szelenkov@nginx.com            'Host': 'localhost',
274603Szelenkov@nginx.com            'Input-Length': '5',
275603Szelenkov@nginx.com            'Connection': 'close'
276603Szelenkov@nginx.com        }, body=body)
277603Szelenkov@nginx.com
278603Szelenkov@nginx.com        self.assertEqual(resp['body'], body[:5], 'input read length lt body')
279603Szelenkov@nginx.com
280603Szelenkov@nginx.com        resp = self.post(headers={
281603Szelenkov@nginx.com            'Host': 'localhost',
282603Szelenkov@nginx.com            'Input-Length': '15',
283603Szelenkov@nginx.com            'Connection': 'close'
284603Szelenkov@nginx.com        }, body=body)
285603Szelenkov@nginx.com
286603Szelenkov@nginx.com        self.assertEqual(resp['body'], body, 'input read length gt body')
287603Szelenkov@nginx.com
288603Szelenkov@nginx.com        resp = self.post(headers={
289603Szelenkov@nginx.com            'Host': 'localhost',
290603Szelenkov@nginx.com            'Input-Length': '0',
291603Szelenkov@nginx.com            'Connection': 'close'
292603Szelenkov@nginx.com        }, body=body)
293603Szelenkov@nginx.com
294603Szelenkov@nginx.com        self.assertEqual(resp['body'], '', 'input read length zero')
295603Szelenkov@nginx.com
296603Szelenkov@nginx.com        resp = self.post(headers={
297603Szelenkov@nginx.com            'Host': 'localhost',
298603Szelenkov@nginx.com            'Input-Length': '-1',
299603Szelenkov@nginx.com            'Connection': 'close'
300603Szelenkov@nginx.com        }, body=body)
301603Szelenkov@nginx.com
302603Szelenkov@nginx.com        self.assertEqual(resp['body'], body, 'input read length negative')
303603Szelenkov@nginx.com
304603Szelenkov@nginx.com    @unittest.expectedFailure
305603Szelenkov@nginx.com    def test_python_application_errors_write(self):
306603Szelenkov@nginx.com        self.load('errors_write')
307603Szelenkov@nginx.com
308603Szelenkov@nginx.com        self.get()
309603Szelenkov@nginx.com
310603Szelenkov@nginx.com        self.stop()
311603Szelenkov@nginx.com
312603Szelenkov@nginx.com        self.assertIsNotNone(
313603Szelenkov@nginx.com            self.search_in_log(r'\[error\].+Error in application\.'),
314603Szelenkov@nginx.com            'errors write')
315603Szelenkov@nginx.com
316603Szelenkov@nginx.com    def test_python_application_body_array(self):
317603Szelenkov@nginx.com        self.load('body_array')
318603Szelenkov@nginx.com
319603Szelenkov@nginx.com        self.assertEqual(self.get()['body'], '0123456789', 'body array')
320603Szelenkov@nginx.com
321603Szelenkov@nginx.com    def test_python_application_body_io(self):
322603Szelenkov@nginx.com        self.load('body_io')
323603Szelenkov@nginx.com
324603Szelenkov@nginx.com        self.assertEqual(self.get()['body'], '0123456789', 'body io')
325603Szelenkov@nginx.com
326603Szelenkov@nginx.com    def test_python_application_body_io_file(self):
327603Szelenkov@nginx.com        self.load('body_io_file')
328603Szelenkov@nginx.com
329603Szelenkov@nginx.com        self.assertEqual(self.get()['body'], 'body\n', 'body io file')
330603Szelenkov@nginx.com
331603Szelenkov@nginx.com    @unittest.expectedFailure
332603Szelenkov@nginx.com    def test_python_application_syntax_error(self):
333603Szelenkov@nginx.com        self.skip_alerts.append(r'Python failed to import module "wsgi"')
334603Szelenkov@nginx.com        self.load('syntax_error')
335603Szelenkov@nginx.com
336603Szelenkov@nginx.com        self.assertEqual(self.get()['status'], 500, 'syntax error')
337603Szelenkov@nginx.com
338603Szelenkov@nginx.com    def test_python_application_close(self):
339603Szelenkov@nginx.com        self.load('close')
340603Szelenkov@nginx.com
341603Szelenkov@nginx.com        self.get()
342603Szelenkov@nginx.com
343603Szelenkov@nginx.com        self.stop()
344603Szelenkov@nginx.com
345603Szelenkov@nginx.com        self.assertIsNotNone(self.search_in_log(r'Close called\.'), 'close')
346603Szelenkov@nginx.com
347603Szelenkov@nginx.com    def test_python_application_close_error(self):
348603Szelenkov@nginx.com        self.load('close_error')
349603Szelenkov@nginx.com
350603Szelenkov@nginx.com        self.get()
351603Szelenkov@nginx.com
352603Szelenkov@nginx.com        self.stop()
353603Szelenkov@nginx.com
354603Szelenkov@nginx.com        self.assertIsNotNone(self.search_in_log(r'Close called\.'),
355603Szelenkov@nginx.com            'close error')
356603Szelenkov@nginx.com
357617Szelenkov@nginx.com    def test_python_application_not_iterable(self):
358617Szelenkov@nginx.com        self.load('not_iterable')
359617Szelenkov@nginx.com
360665Szelenkov@nginx.com        self.get()
361617Szelenkov@nginx.com
362617Szelenkov@nginx.com        self.stop()
363617Szelenkov@nginx.com
364617Szelenkov@nginx.com        self.assertIsNotNone(self.search_in_log(
365617Szelenkov@nginx.com            r'\[error\].+the application returned not an iterable object'),
366617Szelenkov@nginx.com            'not iterable')
367617Szelenkov@nginx.com
368664Szelenkov@nginx.com    def test_python_application_write(self):
369664Szelenkov@nginx.com        self.load('write')
370664Szelenkov@nginx.com
371664Szelenkov@nginx.com        self.assertEqual(self.get()['body'], '0123456789', 'write')
372664Szelenkov@nginx.com
373484Szelenkov@nginx.comif __name__ == '__main__':
374853Szelenkov@nginx.com    TestUnitPythonApplication.main()
375