From f9a3328a2510e7237b8bd8f35a57914f6a22bbd2 Mon Sep 17 00:00:00 2001 From: Andrey Zelenkov Date: Mon, 24 Dec 2018 20:35:18 +0300 Subject: Tests: more QUERY_STRING tests. --- test/php/query_string/index.php | 4 ++++ test/test_perl_application.py | 19 +++++++++++++++++++ test/test_php_application.py | 27 +++++++++++++++++++++++++++ test/test_python_application.py | 19 +++++++++++++++++++ test/test_ruby_application.py | 19 +++++++++++++++++++ 5 files changed, 88 insertions(+) create mode 100644 test/php/query_string/index.php (limited to 'test') diff --git a/test/php/query_string/index.php b/test/php/query_string/index.php new file mode 100644 index 00000000..5691324d --- /dev/null +++ b/test/php/query_string/index.php @@ -0,0 +1,4 @@ + diff --git a/test/test_perl_application.py b/test/test_perl_application.py index c9cb3f0c..2dfae66c 100644 --- a/test/test_perl_application.py +++ b/test/test_perl_application.py @@ -55,6 +55,25 @@ class TestUnitPerlApplication(unit.TestUnitApplicationPerl): self.assertEqual(resp['headers']['Query-String'], 'var1=val1&var2=val2', 'Query-String header') + def test_perl_application_query_string_empty(self): + self.load('query_string') + + resp = self.get(url='/?') + + self.assertEqual(resp['status'], 200, 'query string empty status') + self.assertEqual(resp['headers']['Query-String'], '', + 'query string empty') + + @unittest.expectedFailure + def test_perl_application_query_string_absent(self): + self.load('query_string') + + resp = self.get() + + self.assertEqual(resp['status'], 200, 'query string absent status') + self.assertEqual(resp['headers']['Query-String'], '', + 'query string absent') + @unittest.expectedFailure def test_perl_application_server_port(self): self.load('server_port') diff --git a/test/test_php_application.py b/test/test_php_application.py index e0058d9a..ba9c03b3 100644 --- a/test/test_php_application.py +++ b/test/test_php_application.py @@ -48,6 +48,33 @@ class TestUnitPHPApplication(unit.TestUnitApplicationPHP): }, 'headers') self.assertEqual(resp['body'], body, 'body') + def test_php_application_query_string(self): + self.load('query_string') + + resp = self.get(url='/?var1=val1&var2=val2') + + self.assertEqual(resp['headers']['Query-String'], 'var1=val1&var2=val2', + 'query string') + + def test_php_application_query_string_empty(self): + self.load('query_string') + + resp = self.get(url='/?') + + self.assertEqual(resp['status'], 200, 'query string empty status') + self.assertEqual(resp['headers']['Query-String'], '', + 'query string empty') + + @unittest.expectedFailure + def test_php_application_query_string_absent(self): + self.load('query_string') + + resp = self.get() + + self.assertEqual(resp['status'], 200, 'query string absent status') + self.assertEqual(resp['headers']['Query-String'], '', + 'query string absent') + def test_php_application_phpinfo(self): self.load('phpinfo') diff --git a/test/test_python_application.py b/test/test_python_application.py index 667047bc..9c2c762d 100644 --- a/test/test_python_application.py +++ b/test/test_python_application.py @@ -53,6 +53,25 @@ class TestUnitPythonApplication(unit.TestUnitApplicationPython): self.assertEqual(resp['headers']['Query-String'], 'var1=val1&var2=val2', 'Query-String header') + def test_python_application_query_string_empty(self): + self.load('query_string') + + resp = self.get(url='/?') + + self.assertEqual(resp['status'], 200, 'query string empty status') + self.assertEqual(resp['headers']['Query-String'], '', + 'query string empty') + + @unittest.expectedFailure + def test_python_application_query_string_absent(self): + self.load('query_string') + + resp = self.get() + + self.assertEqual(resp['status'], 200, 'query string absent status') + self.assertEqual(resp['headers']['Query-String'], '', + 'query string absent') + @unittest.expectedFailure def test_python_application_server_port(self): self.load('server_port') diff --git a/test/test_ruby_application.py b/test/test_ruby_application.py index 57ab88cd..b88e043d 100644 --- a/test/test_ruby_application.py +++ b/test/test_ruby_application.py @@ -56,6 +56,25 @@ class TestUnitRubyApplication(unit.TestUnitApplicationRuby): self.assertEqual(resp['headers']['Query-String'], 'var1=val1&var2=val2', 'Query-String header') + def test_ruby_application_query_string_empty(self): + self.load('query_string') + + resp = self.get(url='/?') + + self.assertEqual(resp['status'], 200, 'query string empty status') + self.assertEqual(resp['headers']['Query-String'], '', + 'query string empty') + + @unittest.expectedFailure + def test_ruby_application_query_string_absent(self): + self.load('query_string') + + resp = self.get() + + self.assertEqual(resp['status'], 200, 'query string absent status') + self.assertEqual(resp['headers']['Query-String'], '', + 'query string absent') + @unittest.expectedFailure def test_ruby_application_server_port(self): self.load('server_port') -- cgit From f57e729a119660182d333f513b70b78177eb2b62 Mon Sep 17 00:00:00 2001 From: Andrey Zelenkov Date: Tue, 25 Dec 2018 16:35:35 +0300 Subject: Tests: expectedFailure's removed from test_node_application.py. Also removed alert skip in test_node_application_write_before_writeHead. Fixes committed in 1340e3539362, 1e008ef94f43, 5df32621af19, dae402cb243f and 41f561b3a178. --- test/test_node_application.py | 7 ------- 1 file changed, 7 deletions(-) (limited to 'test') diff --git a/test/test_node_application.py b/test/test_node_application.py index 5dedb5a3..a9f5b8a3 100644 --- a/test/test_node_application.py +++ b/test/test_node_application.py @@ -112,7 +112,6 @@ class TestUnitNodeApplication(unit.TestUnitApplicationNode): self.assertEqual(self.get()['body'], '6\r\nbuffer\r\n0\r\n\r\n', 'write buffer') - @unittest.expectedFailure def test_node_application_write_callback(self): self.load('write_callback') @@ -122,7 +121,6 @@ class TestUnitNodeApplication(unit.TestUnitApplicationNode): 'write callback') def test_node_application_write_before_writeHead(self): - self.skip_alerts.append(r'process \d+ exited on signal') self.load('write_before_write_head') self.get() @@ -182,7 +180,6 @@ class TestUnitNodeApplication(unit.TestUnitApplicationNode): self.assertEqual(self.get()['headers']['X-Type'], 'number', 'get header type') - @unittest.expectedFailure def test_node_application_header_name_case(self): self.load('header_name_case') @@ -202,9 +199,7 @@ class TestUnitNodeApplication(unit.TestUnitApplicationNode): self.assertTrue(self.waitforfiles(self.testdir + '/node/callback'), 'promise handler') - @unittest.expectedFailure def test_node_application_promise_handler_write_after_end(self): - self.skip_alerts.append(r'process \d+ exited on signal') self.load('promise_handler') self.assertEqual(self.post(headers={ @@ -249,13 +244,11 @@ class TestUnitNodeApplication(unit.TestUnitApplicationNode): self.assertNotIn('status', self.get(), 'header name valid') - @unittest.expectedFailure def test_node_application_header_value_object(self): self.load('header_value_object') self.assertIn('X-Header', self.get()['headers'], 'header value object') - @unittest.expectedFailure def test_node_application_get_header_names(self): self.load('get_header_names') -- cgit From d625691ff45bd6f352a504694629af2407a7d1a1 Mon Sep 17 00:00:00 2001 From: Andrey Zelenkov Date: Tue, 25 Dec 2018 16:35:35 +0300 Subject: Tests: test_node_application_write_before_writeHead reworked. Added res.end() call in application and response status check. Also, renamed to test_node_application_write_before_write_head. --- test/node/write_before_write_head/app.js | 1 + test/test_node_application.py | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) (limited to 'test') diff --git a/test/node/write_before_write_head/app.js b/test/node/write_before_write_head/app.js index 9fe3a58d..6e3fb9a9 100755 --- a/test/node/write_before_write_head/app.js +++ b/test/node/write_before_write_head/app.js @@ -3,4 +3,5 @@ require('unit-http').createServer(function (req, res) { res.write('blah'); res.writeHead(200, {'Content-Type': 'text/plain'}); + res.end(); }).listen(7080); diff --git a/test/test_node_application.py b/test/test_node_application.py index a9f5b8a3..05b518f5 100644 --- a/test/test_node_application.py +++ b/test/test_node_application.py @@ -120,10 +120,10 @@ class TestUnitNodeApplication(unit.TestUnitApplicationNode): self.assertTrue(self.waitforfiles(self.testdir + '/node/callback'), 'write callback') - def test_node_application_write_before_writeHead(self): + def test_node_application_write_before_write_head(self): self.load('write_before_write_head') - self.get() + self.assertEqual(self.get()['status'], 200, 'write before writeHead') def test_node_application_double_end(self): self.load('double_end') -- cgit From f5b7fee128dfabc3225e05a69a5c9458b63c315b Mon Sep 17 00:00:00 2001 From: Andrey Zelenkov Date: Tue, 25 Dec 2018 16:35:35 +0300 Subject: Tests: set TCP_NODELAY option by default. --- test/unit.py | 3 +++ 1 file changed, 3 insertions(+) (limited to 'test') diff --git a/test/unit.py b/test/unit.py index e88ed684..2b95b792 100644 --- a/test/unit.py +++ b/test/unit.py @@ -309,6 +309,9 @@ class TestUnitHTTP(TestUnit): if 'sock' not in kwargs: sock = socket.socket(sock_types[sock_type], socket.SOCK_STREAM) + if sock_type == sock_types['ipv4'] or sock_type == sock_types['ipv6']: + sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1) + if 'wrapper' in kwargs: sock = kwargs['wrapper'](sock) -- cgit From 4ccf0c8a17d4f481cbb9b4047da30cbec5497c46 Mon Sep 17 00:00:00 2001 From: Andrey Zelenkov Date: Tue, 25 Dec 2018 16:35:35 +0300 Subject: Tests: fixed test_tls_reconfigure. Previously, order of applying TLS configuration and sending partial request to the application was uncertain. These changes make sure that client-application connection was established before reconfiguration. Additionally, added test to check that non-TLS connection works correctly after reconfiguration. --- test/test_tls.py | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) (limited to 'test') diff --git a/test/test_tls.py b/test/test_tls.py index fa5c9754..dc2f4505 100644 --- a/test/test_tls.py +++ b/test/test_tls.py @@ -306,23 +306,25 @@ basicConstraints = critical,CA:TRUE""" % { self.assertEqual(self.get_ssl()['status'], 200, 'certificate chain intermediate server') + @unittest.expectedFailure def test_tls_reconfigure(self): self.load('empty') self.certificate() - (resp, sock) = self.http(b"""GET / HTTP/1.1 -""", start=True, raw=True, no_recv=True) - - self.add_tls() + (resp, sock) = self.get(headers={ + 'Connection': 'keep-alive', + 'Host': 'localhost' + }, start=True) - resp = self.http(b"""Host: localhost -Connection: close + self.assertEqual(resp['status'], 200, 'initial status') -""", sock=sock, raw=True) + self.add_tls() - self.assertEqual(resp['status'], 200, 'update status') - self.assertEqual(self.get_ssl()['status'], 200, 'update tls status') + self.assertEqual(self.get(sock=sock)['status'], 200, + 'reconfigure status') + self.assertEqual(self.get_ssl()['status'], 200, + 'reconfigure tls status') def test_tls_keepalive(self): self.load('mirror') -- cgit From 59644130668c19522488932fbe894587e5616a94 Mon Sep 17 00:00:00 2001 From: Andrey Zelenkov Date: Tue, 25 Dec 2018 17:22:32 +0300 Subject: Tests: added delay to wait for error logging. --- test/test_python_application.py | 3 +++ 1 file changed, 3 insertions(+) (limited to 'test') diff --git a/test/test_python_application.py b/test/test_python_application.py index 9c2c762d..b28675f9 100644 --- a/test/test_python_application.py +++ b/test/test_python_application.py @@ -1,3 +1,4 @@ +import time import unittest import unit @@ -105,6 +106,8 @@ class TestUnitPythonApplication(unit.TestUnitApplicationPython): self.stop() + time.sleep(0.2) + self.assertIsNotNone(self.search_in_log(r'RuntimeError'), 'ctx iter atexit') -- cgit From 17068d2cdc1f0287f4d072e0d3a5694c8dd38e22 Mon Sep 17 00:00:00 2001 From: Andrey Zelenkov Date: Tue, 25 Dec 2018 21:28:02 +0300 Subject: Tests: removed skipping Go tests on x86. --- test/test_go_application.py | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) (limited to 'test') diff --git a/test/test_go_application.py b/test/test_go_application.py index fd80bf5b..90785851 100644 --- a/test/test_go_application.py +++ b/test/test_go_application.py @@ -4,12 +4,7 @@ import unit class TestUnitGoApplication(unit.TestUnitApplicationGo): def setUpClass(): - u = unit.TestUnit() - - if u.architecture == '32bit': - raise unittest.SkipTest('Skip Go tests for x86') - - u.check_modules('go') + unit.TestUnit().check_modules('go') def test_go_application_variables(self): self.load('variables') -- cgit From eced6bc97284478d67bfec04e204e4cd212167d9 Mon Sep 17 00:00:00 2001 From: Andrey Zelenkov Date: Mon, 28 Jan 2019 15:11:50 +0300 Subject: Tests: removed blocking mode customization for sockets. This customization was added in 0e12b17e512d and left unused. Also, set blocking mode by default for all sockets. --- test/unit.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) (limited to 'test') diff --git a/test/unit.py b/test/unit.py index 2b95b792..55b3ce18 100644 --- a/test/unit.py +++ b/test/unit.py @@ -285,7 +285,6 @@ class TestUnitHTTP(TestUnit): port = 7080 if 'port' not in kwargs else kwargs['port'] url = '/' if 'url' not in kwargs else kwargs['url'] http = 'HTTP/1.0' if 'http_10' in kwargs else 'HTTP/1.1' - blocking = False if 'blocking' not in kwargs else kwargs['blocking'] headers = ({ 'Host': 'localhost', @@ -322,8 +321,6 @@ class TestUnitHTTP(TestUnit): sock.close() return None - sock.setblocking(blocking) - else: sock = kwargs['sock'] @@ -640,11 +637,11 @@ class TestUnitApplicationTLS(TestUnitApplicationProto): return self.conf(k.read() + c.read(), '/certificates/' + crt) def get_ssl(self, **kwargs): - return self.get(blocking=True, wrapper=self.context.wrap_socket, + return self.get(wrapper=self.context.wrap_socket, **kwargs) def post_ssl(self, **kwargs): - return self.post(blocking=True, wrapper=self.context.wrap_socket, + return self.post(wrapper=self.context.wrap_socket, **kwargs) def get_server_certificate(self, addr=('127.0.0.1', 7080)): -- cgit From 7dddfe2143e28dcde147d8420f0bd129babaec3a Mon Sep 17 00:00:00 2001 From: Andrey Zelenkov Date: Mon, 28 Jan 2019 17:16:50 +0300 Subject: Tests: added test for reading body from IO::Handle-like object. --- test/perl/body_io_fake/IOFake.pm | 33 +++++++++++++++++++++++++++++++++ test/perl/body_io_fake/psgi.pl | 11 +++++++++++ test/test_perl_application.py | 14 ++++++++++++++ 3 files changed, 58 insertions(+) create mode 100644 test/perl/body_io_fake/IOFake.pm create mode 100644 test/perl/body_io_fake/psgi.pl (limited to 'test') diff --git a/test/perl/body_io_fake/IOFake.pm b/test/perl/body_io_fake/IOFake.pm new file mode 100644 index 00000000..d2542aa5 --- /dev/null +++ b/test/perl/body_io_fake/IOFake.pm @@ -0,0 +1,33 @@ +package IOFake; + +sub new { + my $class = shift; + my $errors = shift; + my $self = {}; + + $self->{_count} = 2; + $self->{_errors} = $errors; + + bless $self, $class; + return $self; +} + +sub getline() { + my $self = shift; + + if ($self->{_count} > 0) { + return $self->{_count}--; + } + + $self->{_errors}->print('IOFake getline() $/ is ' . ${ $/ }); + + return; +} + +sub close() { + my $self = shift; + + $self->{_errors}->print('IOFake close() called'); +}; + +1; diff --git a/test/perl/body_io_fake/psgi.pl b/test/perl/body_io_fake/psgi.pl new file mode 100644 index 00000000..6990bfaf --- /dev/null +++ b/test/perl/body_io_fake/psgi.pl @@ -0,0 +1,11 @@ +use File::Basename; +use lib dirname (__FILE__); +use IOFake; + +my $app = sub { + my ($environ) = @_; + + my $io = IOFake->new($environ->{'psgi.errors'}); + + return ['200', [ 'Content-Length' => '2' ], $io]; +}; diff --git a/test/test_perl_application.py b/test/test_perl_application.py index 2dfae66c..7850e231 100644 --- a/test/test_perl_application.py +++ b/test/test_perl_application.py @@ -185,5 +185,19 @@ class TestUnitPerlApplication(unit.TestUnitApplicationPerl): self.assertEqual(resp['body'], '0123456789', 'keep-alive 2') + @unittest.expectedFailure + def test_perl_body_io_fake(self): + self.load('body_io_fake') + + self.assertEqual(self.get()['body'], '21', 'body io fake') + + self.assertIsNotNone( + self.search_in_log(r'\[error\].+IOFake getline\(\) \$\/ is \d+'), + 'body io fake $/ value') + + self.assertIsNotNone( + self.search_in_log(r'\[error\].+IOFake close\(\) called'), + 'body io fake close') + if __name__ == '__main__': TestUnitPerlApplication.main() -- cgit From d60fbc6d4476982fb683d485859acd2c29a6837c Mon Sep 17 00:00:00 2001 From: Andrey Zelenkov Date: Mon, 28 Jan 2019 17:17:23 +0300 Subject: Tests: large configuration tests. --- test/test_configuration.py | 47 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) (limited to 'test') diff --git a/test/test_configuration.py b/test/test_configuration.py index 02705afe..7f81b86b 100644 --- a/test/test_configuration.py +++ b/test/test_configuration.py @@ -217,5 +217,52 @@ class TestUnitConfiguration(unit.TestUnitControl): } }), 'no port') + @unittest.expectedFailure + def test_json_application_name_large(self): + self.skip_alerts.append(r'epoll_ctl.+failed') + name = "X" * 1024 * 1024 + + self.assertIn('success', self.conf({ + "listeners": { + "*:7080": { + "application": name + } + }, + "applications": { + name: { + "type": "python", + "processes": { "spare": 0 }, + "path": "/app", + "module": "wsgi" + } + } + })) + + @unittest.expectedFailure + def test_json_application_many(self): + self.skip_alerts.extend([ + r'eventfd.+failed', + r'failed to apply new conf' + ]) + apps = 1000 + + conf = { + "applications": + {"app-" + str(a): { + "type": "python", + "processes": { "spare": 0 }, + "path": "/app", + "module": "wsgi" + } for a in range(apps) + }, + "listeners": { + "*:" + str(7080 + a): { + "application": "app-" + str(a) + } for a in range(apps) + } + } + + self.assertIn('success', self.conf(conf)) + if __name__ == '__main__': TestUnitConfiguration.main() -- cgit From 7ce9f61cb66ddd78e2a6778970cd7c4845c79f00 Mon Sep 17 00:00:00 2001 From: Andrey Zelenkov Date: Thu, 14 Feb 2019 16:09:19 +0300 Subject: Tests: minor fixes. --- test/test_settings.py | 2 -- test/unit.py | 6 +++--- 2 files changed, 3 insertions(+), 5 deletions(-) (limited to 'test') diff --git a/test/test_settings.py b/test/test_settings.py index b4ac33dc..d272f701 100644 --- a/test/test_settings.py +++ b/test/test_settings.py @@ -28,8 +28,6 @@ Connection: close def test_settings_header_read_timeout_update(self): self.load('empty') - r = None - self.conf({'http': { 'header_read_timeout': 4 }}, 'settings') (resp, sock) = self.http(b"""GET / HTTP/1.1 diff --git a/test/unit.py b/test/unit.py index 55b3ce18..c0c65d4a 100644 --- a/test/unit.py +++ b/test/unit.py @@ -235,7 +235,7 @@ class TestUnit(unittest.TestCase): if sanitizer_errors: self._print_path_to_log() - self.assertFalse(sanitizer_error, 'sanitizer error(s)') + self.assertFalse(sanitizer_errors, 'sanitizer error(s)') if found: print('skipped.') @@ -350,8 +350,8 @@ class TestUnitHTTP(TestUnit): resp = '' if 'no_recv' not in kwargs: - enc = 'utf-8' if 'encoding' not in kwargs else kwargs['encoding'] - resp = self.recvall(sock).decode(enc) + enc = 'utf-8' if 'encoding' not in kwargs else kwargs['encoding'] + resp = self.recvall(sock).decode(enc) if TestUnit.detailed: print('<<<', resp.encode('utf-8'), sep='\n') -- cgit From 0e5aaf60d4ca2da509a6a73bebe71139f8aae306 Mon Sep 17 00:00:00 2001 From: Andrey Zelenkov Date: Thu, 14 Feb 2019 16:09:54 +0300 Subject: Tests: headers with equal header fields allowed. --- test/unit.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'test') diff --git a/test/unit.py b/test/unit.py index c0c65d4a..bd6128cc 100644 --- a/test/unit.py +++ b/test/unit.py @@ -335,7 +335,12 @@ class TestUnitHTTP(TestUnit): headers['Content-Length'] = len(body) for header, value in headers.items(): - req += header + ': ' + str(value) + crlf + if isinstance(value, list): + for v in value: + req += header + ': ' + str(v) + crlf + + else: + req += header + ': ' + str(value) + crlf req = (req + crlf).encode() + body -- cgit From ab40732c0886b979090da6245cc1a7f0ba52de49 Mon Sep 17 00:00:00 2001 From: Andrey Zelenkov Date: Thu, 14 Feb 2019 16:09:58 +0300 Subject: Tests: added tests for "Content-Length" header. --- test/test_http_header.py | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) (limited to 'test') diff --git a/test/test_http_header.py b/test/test_http_header.py index b850831d..7894c94e 100644 --- a/test/test_http_header.py +++ b/test/test_http_header.py @@ -162,5 +162,51 @@ a self.assertEqual(resp['status'], 200, 'transfer encoding chunked') + def test_http_header_content_length_big(self): + self.load('empty') + + self.assertEqual(self.post(headers={ + 'Content-Length': str(2 ** 64), + 'Connection': 'close', + 'Host': 'localhost' + }, body='X' * 1000)['status'], 400, 'Content-Length big') + + def test_http_header_content_length_negative(self): + self.load('empty') + + self.assertEqual(self.post(headers={ + 'Content-Length': '-100', + 'Connection': 'close', + 'Host': 'localhost' + }, body='X' * 1000)['status'], 400, 'Content-Length negative') + + def test_http_header_content_length_text(self): + self.load('empty') + + self.assertEqual(self.post(headers={ + 'Content-Length': 'blah', + 'Connection': 'close', + 'Host': 'localhost' + }, body='X' * 1000)['status'], 400, 'Content-Length text') + + def test_http_header_content_length_multiple_values(self): + self.load('empty') + + self.assertEqual(self.post(headers={ + 'Content-Length': '41, 42', + 'Connection': 'close', + 'Host': 'localhost' + }, body='X' * 1000)['status'], 400, 'Content-Length multiple value') + + @unittest.expectedFailure + def test_http_header_content_length_multiple_fields(self): + self.load('empty') + + self.assertEqual(self.post(headers={ + 'Content-Length': ['41', '42'], + 'Connection': 'close', + 'Host': 'localhost' + }, body='X' * 1000)['status'], 400, 'Content-Length multiple fields') + if __name__ == '__main__': TestUnitHTTPHeader.main() -- cgit From 2a6b54c23020a24eaadfb4006235ca17dfa877f8 Mon Sep 17 00:00:00 2001 From: Valentin Bartenev Date: Mon, 18 Feb 2019 16:51:30 +0300 Subject: Rejecting requests with duplicate "Content-Length". --- test/test_http_header.py | 1 - 1 file changed, 1 deletion(-) (limited to 'test') diff --git a/test/test_http_header.py b/test/test_http_header.py index 7894c94e..5a982217 100644 --- a/test/test_http_header.py +++ b/test/test_http_header.py @@ -198,7 +198,6 @@ a 'Host': 'localhost' }, body='X' * 1000)['status'], 400, 'Content-Length multiple value') - @unittest.expectedFailure def test_http_header_content_length_multiple_fields(self): self.load('empty') -- cgit From ac10bf8c7b4cbfb9421956ba8ee3005bb7f4fbfa Mon Sep 17 00:00:00 2001 From: Andrey Zelenkov Date: Wed, 20 Feb 2019 20:19:55 +0300 Subject: Tests: fixed ports range. --- test/test_configuration.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'test') diff --git a/test/test_configuration.py b/test/test_configuration.py index 7f81b86b..d6c9cd5c 100644 --- a/test/test_configuration.py +++ b/test/test_configuration.py @@ -244,7 +244,7 @@ class TestUnitConfiguration(unit.TestUnitControl): r'eventfd.+failed', r'failed to apply new conf' ]) - apps = 1000 + apps = 999 conf = { "applications": @@ -256,7 +256,7 @@ class TestUnitConfiguration(unit.TestUnitControl): } for a in range(apps) }, "listeners": { - "*:" + str(7080 + a): { + "*:" + str(7000 + a): { "application": "app-" + str(a) } for a in range(apps) } -- cgit From b2ca342902ec84b4415982be08d89c8bfe0ed431 Mon Sep 17 00:00:00 2001 From: Andrey Zelenkov Date: Wed, 20 Feb 2019 20:20:02 +0300 Subject: Tests: JSON array allowed. --- test/unit.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'test') diff --git a/test/unit.py b/test/unit.py index bd6128cc..2af3e8f6 100644 --- a/test/unit.py +++ b/test/unit.py @@ -433,7 +433,7 @@ class TestUnitControl(TestUnitHTTP): # TODO http client def conf(self, conf, path='/config'): - if isinstance(conf, dict): + if isinstance(conf, dict) or isinstance(conf, list): conf = json.dumps(conf) if path[:1] != '/': -- cgit From 09fb847cc731d133b2016ff6982ab95aa43794ca Mon Sep 17 00:00:00 2001 From: Andrey Zelenkov Date: Wed, 20 Feb 2019 20:24:05 +0300 Subject: Tests: removed test_http_header_transfer_encoding_chunked. --- test/test_http_header.py | 17 ----------------- 1 file changed, 17 deletions(-) (limited to 'test') diff --git a/test/test_http_header.py b/test/test_http_header.py index 5a982217..0544f3b3 100644 --- a/test/test_http_header.py +++ b/test/test_http_header.py @@ -145,23 +145,6 @@ Connection: close self.assertEqual(resp['status'], 400, 'field trailing htab') - @unittest.expectedFailure - def test_http_header_transfer_encoding_chunked(self): - self.load('empty') - - resp = self.http(b"""GET / HTTP/1.1 -Host: localhost -Transfer-Encoding: chunked -Connection: close - -a -0123456789 -0 - -""", raw=True) - - self.assertEqual(resp['status'], 200, 'transfer encoding chunked') - def test_http_header_content_length_big(self): self.load('empty') -- cgit From 955050aea3148595fde027319fd427369856ebc9 Mon Sep 17 00:00:00 2001 From: Andrey Zelenkov Date: Wed, 20 Feb 2019 20:28:29 +0300 Subject: Tests: skip sendmsg()/recvmsg() alerts for all tests. Currently, these alerts may appear in the log when any application exits. --- test/test_configuration.py | 1 - test/test_python_application.py | 8 -------- test/test_ruby_application.py | 1 - test/unit.py | 3 ++- 4 files changed, 2 insertions(+), 11 deletions(-) (limited to 'test') diff --git a/test/test_configuration.py b/test/test_configuration.py index d6c9cd5c..32c5a0b7 100644 --- a/test/test_configuration.py +++ b/test/test_configuration.py @@ -132,7 +132,6 @@ class TestUnitConfiguration(unit.TestUnitControl): self.skip_sanitizer = True self.skip_alerts.extend([ r'failed to apply previous configuration', - r'sendmsg.+failed', r'process \d+ exited on signal' ]) diff --git a/test/test_python_application.py b/test/test_python_application.py index b28675f9..d37af0c4 100644 --- a/test/test_python_application.py +++ b/test/test_python_application.py @@ -87,7 +87,6 @@ class TestUnitPythonApplication(unit.TestUnitApplicationPython): '204 header transfer encoding') def test_python_application_ctx_iter_atexit(self): - self.skip_alerts.append(r'sendmsg.+failed') self.load('ctx_iter_atexit') resp = self.post(headers={ @@ -131,10 +130,6 @@ class TestUnitPythonApplication(unit.TestUnitApplicationPython): self.assertEqual(resp['body'], '0123456789', 'keep-alive 2') def test_python_keepalive_reconfigure(self): - self.skip_alerts.extend([ - r'sendmsg.+failed', - r'recvmsg.+failed' - ]) self.load('mirror') body = '0123456789' @@ -183,7 +178,6 @@ class TestUnitPythonApplication(unit.TestUnitApplicationPython): }, 'applications/mirror/processes'), 'reconfigure 3') def test_python_keepalive_reconfigure_2(self): - self.skip_alerts.append(r'sendmsg.+failed') self.load('mirror') body = '0123456789' @@ -217,7 +211,6 @@ class TestUnitPythonApplication(unit.TestUnitApplicationPython): self.assertEqual(resp, {}, 'reconfigure 2 keep-alive 3') def test_python_keepalive_reconfigure_3(self): - self.skip_alerts.append(r'sendmsg.+failed') self.load('empty') (resp, sock) = self.http(b"""GET / HTTP/1.1 @@ -236,7 +229,6 @@ Connection: close self.assertEqual(resp['status'], 200, 'reconfigure 3') def test_python_atexit(self): - self.skip_alerts.append(r'sendmsg.+failed') self.load('atexit') self.get() diff --git a/test/test_ruby_application.py b/test/test_ruby_application.py index b88e043d..9eed3e4a 100644 --- a/test/test_ruby_application.py +++ b/test/test_ruby_application.py @@ -208,7 +208,6 @@ class TestUnitRubyApplication(unit.TestUnitApplicationRuby): 'errors write int') def test_ruby_application_at_exit(self): - self.skip_alerts.append(r'sendmsg.+failed') self.load('at_exit') self.get() diff --git a/test/unit.py b/test/unit.py index 2af3e8f6..80e26e0d 100644 --- a/test/unit.py +++ b/test/unit.py @@ -179,7 +179,8 @@ class TestUnit(unittest.TestCase): self._started = True - self.skip_alerts = [r'read signalfd\(4\) failed'] + self.skip_alerts = [r'read signalfd\(4\) failed', r'sendmsg.+failed', + r'recvmsg.+failed'] self.skip_sanitizer = False def _stop(self): -- cgit From 499096a55a681609a9b655059e2f56638bcf104e Mon Sep 17 00:00:00 2001 From: Andrey Zelenkov Date: Wed, 20 Feb 2019 20:46:23 +0300 Subject: Tests: one more alert skipped in test_json_application_many. --- test/test_configuration.py | 1 + 1 file changed, 1 insertion(+) (limited to 'test') diff --git a/test/test_configuration.py b/test/test_configuration.py index 32c5a0b7..52a67d38 100644 --- a/test/test_configuration.py +++ b/test/test_configuration.py @@ -241,6 +241,7 @@ class TestUnitConfiguration(unit.TestUnitControl): def test_json_application_many(self): self.skip_alerts.extend([ r'eventfd.+failed', + r'epoll_create.+failed', r'failed to apply new conf' ]) apps = 999 -- cgit From 379e4c75fdf99439e481f739324d9c6d6d1b18ab Mon Sep 17 00:00:00 2001 From: Alexander Borisov Date: Wed, 27 Feb 2019 17:27:41 +0300 Subject: Perl: added processing for IO:Handle-like object. The application can return the body as an IO:Handle-like object without file descriptor. --- test/test_perl_application.py | 1 - 1 file changed, 1 deletion(-) (limited to 'test') diff --git a/test/test_perl_application.py b/test/test_perl_application.py index 7850e231..f9acbd32 100644 --- a/test/test_perl_application.py +++ b/test/test_perl_application.py @@ -185,7 +185,6 @@ class TestUnitPerlApplication(unit.TestUnitApplicationPerl): self.assertEqual(resp['body'], '0123456789', 'keep-alive 2') - @unittest.expectedFailure def test_perl_body_io_fake(self): self.load('body_io_fake') -- cgit From 4de2c8b56719fce6b95b6f8a613b349590a3676f Mon Sep 17 00:00:00 2001 From: Andrey Zelenkov Date: Wed, 27 Feb 2019 19:15:02 +0300 Subject: Tests: added "Host" and "Connetion" headers where necessary. Also minor header organizing. --- test/test_access_log.py | 8 +++--- test/test_go_application.py | 18 ++++++------ test/test_http_header.py | 64 +++++++++++++++++++++++++++-------------- test/test_node_application.py | 43 ++++++++++++++++----------- test/test_perl_application.py | 12 ++++---- test/test_php_application.py | 12 ++++---- test/test_python_application.py | 36 ++++++++++++----------- test/test_ruby_application.py | 12 ++++---- test/test_settings.py | 9 +++--- test/test_tls.py | 28 +++++++++--------- 10 files changed, 143 insertions(+), 99 deletions(-) (limited to 'test') diff --git a/test/test_access_log.py b/test/test_access_log.py index c8464796..d6741c28 100644 --- a/test/test_access_log.py +++ b/test/test_access_log.py @@ -23,9 +23,9 @@ class TestUnitAccessLog(unit.TestUnitApplicationPython): self.load('mirror') (resp, sock) = self.post(headers={ + 'Host': 'localhost', 'Connection': 'keep-alive', - 'Content-Type': 'text/html', - 'Host': 'localhost' + 'Content-Type': 'text/html' }, start=True, body='01234') time.sleep(0.2) @@ -34,9 +34,9 @@ class TestUnitAccessLog(unit.TestUnitApplicationPython): self.search_in_log(r'"POST / HTTP/1.1" 200 5'), 'keepalive 1') resp = self.post(headers={ + 'Host': 'localhost', 'Connection': 'close', - 'Content-Type': 'text/html', - 'Host': 'localhost' + 'Content-Type': 'text/html' }, sock=sock, body='0123456789') time.sleep(0.2) diff --git a/test/test_go_application.py b/test/test_go_application.py index 90785851..1ecc2536 100644 --- a/test/test_go_application.py +++ b/test/test_go_application.py @@ -14,7 +14,8 @@ class TestUnitGoApplication(unit.TestUnitApplicationGo): resp = self.post(headers={ 'Host': 'localhost', 'Content-Type': 'text/html', - 'Custom-Header': 'blah' + 'Custom-Header': 'blah', + 'Connection': 'close' }, body=body) self.assertEqual(resp['status'], 200, 'status') @@ -36,7 +37,8 @@ class TestUnitGoApplication(unit.TestUnitApplicationGo): 'Server-Protocol': 'HTTP/1.1', 'Server-Protocol-Major': '1', 'Server-Protocol-Minor': '1', - 'Custom-Header': 'blah' + 'Custom-Header': 'blah', + 'Connection': 'close' }, 'headers') self.assertEqual(resp['body'], body, 'body') @@ -52,8 +54,8 @@ class TestUnitGoApplication(unit.TestUnitApplicationGo): self.load('post_variables') resp = self.post(headers={ - 'Content-Type': 'application/x-www-form-urlencoded', 'Host': 'localhost', + 'Content-Type': 'application/x-www-form-urlencoded', 'Connection': 'close' }, body='var1=val1&var2=&var3') @@ -74,17 +76,17 @@ class TestUnitGoApplication(unit.TestUnitApplicationGo): self.load('mirror') (resp, sock) = self.post(headers={ + 'Host': 'localhost', 'Connection': 'keep-alive', - 'Content-Type': 'text/html', - 'Host': 'localhost' + 'Content-Type': 'text/html' }, start=True, body='0123456789' * 500) self.assertEqual(resp['body'], '0123456789' * 500, 'keep-alive 1') resp = self.post(headers={ - 'Connection': 'close', + 'Host': 'localhost', 'Content-Type': 'text/html', - 'Host': 'localhost' + 'Connection': 'close' }, sock=sock, body='0123456789') self.assertEqual(resp['body'], '0123456789', 'keep-alive 2') @@ -93,8 +95,8 @@ class TestUnitGoApplication(unit.TestUnitApplicationGo): self.load('cookies') resp = self.get(headers={ - 'Cookie': 'var1=val1; var2=val2', 'Host': 'localhost', + 'Cookie': 'var1=val1; var2=val2', 'Connection': 'close' }) diff --git a/test/test_http_header.py b/test/test_http_header.py index 0544f3b3..a7638b8d 100644 --- a/test/test_http_header.py +++ b/test/test_http_header.py @@ -10,7 +10,9 @@ class TestUnitHTTPHeader(unit.TestUnitApplicationPython): self.load('custom_header') resp = self.get(headers={ - 'Custom-Header': ' ,' + 'Host': 'localhost', + 'Custom-Header': ' ,', + 'Connection': 'close' }) self.assertEqual(resp['status'], 200, 'value leading sp status') @@ -21,7 +23,9 @@ class TestUnitHTTPHeader(unit.TestUnitApplicationPython): self.load('custom_header') resp = self.get(headers={ - 'Custom-Header': '\t,' + 'Host': 'localhost', + 'Custom-Header': '\t,', + 'Connection': 'close' }) self.assertEqual(resp['status'], 200, 'value leading htab status') @@ -32,7 +36,9 @@ class TestUnitHTTPHeader(unit.TestUnitApplicationPython): self.load('custom_header') resp = self.get(headers={ - 'Custom-Header': ', ' + 'Host': 'localhost', + 'Custom-Header': ', ', + 'Connection': 'close' }) self.assertEqual(resp['status'], 200, 'value trailing sp status') @@ -43,7 +49,9 @@ class TestUnitHTTPHeader(unit.TestUnitApplicationPython): self.load('custom_header') resp = self.get(headers={ - 'Custom-Header': ',\t' + 'Host': 'localhost', + 'Custom-Header': ',\t', + 'Connection': 'close' }) self.assertEqual(resp['status'], 200, 'value trailing htab status') @@ -54,7 +62,9 @@ class TestUnitHTTPHeader(unit.TestUnitApplicationPython): self.load('custom_header') resp = self.get(headers={ - 'Custom-Header': ' , ' + 'Host': 'localhost', + 'Custom-Header': ' , ', + 'Connection': 'close' }) self.assertEqual(resp['status'], 200, 'value both sp status') @@ -65,7 +75,9 @@ class TestUnitHTTPHeader(unit.TestUnitApplicationPython): self.load('custom_header') resp = self.get(headers={ - 'Custom-Header': '\t,\t' + 'Host': 'localhost', + 'Custom-Header': '\t,\t', + 'Connection': 'close' }) self.assertEqual(resp['status'], 200, 'value both htab status') @@ -76,7 +88,9 @@ class TestUnitHTTPHeader(unit.TestUnitApplicationPython): self.load('custom_header') resp = self.get(headers={ - 'Custom-Header': '(),/:;<=>?@[\]{}\t !#$%&\'*+-.^_`|~' + 'Host': 'localhost', + 'Custom-Header': '(),/:;<=>?@[\]{}\t !#$%&\'*+-.^_`|~', + 'Connection': 'close' }) self.assertEqual(resp['status'], 200, 'value chars status') @@ -113,7 +127,9 @@ Connection: close self.load('empty') resp = self.get(headers={ - ' Custom-Header': 'blah' + 'Host': 'localhost', + ' Custom-Header': 'blah', + 'Connection': 'close' }) self.assertEqual(resp['status'], 400, 'field leading sp') @@ -122,7 +138,9 @@ Connection: close self.load('empty') resp = self.get(headers={ - '\tCustom-Header': 'blah' + 'Host': 'localhost', + '\tCustom-Header': 'blah', + 'Connection': 'close' }) self.assertEqual(resp['status'], 400, 'field leading htab') @@ -131,7 +149,9 @@ Connection: close self.load('empty') resp = self.get(headers={ - 'Custom-Header ': 'blah' + 'Host': 'localhost', + 'Custom-Header ': 'blah', + 'Connection': 'close' }) self.assertEqual(resp['status'], 400, 'field trailing sp') @@ -140,7 +160,9 @@ Connection: close self.load('empty') resp = self.get(headers={ - 'Custom-Header\t': 'blah' + 'Host': 'localhost', + 'Custom-Header\t': 'blah', + 'Connection': 'close' }) self.assertEqual(resp['status'], 400, 'field trailing htab') @@ -149,45 +171,45 @@ Connection: close self.load('empty') self.assertEqual(self.post(headers={ + 'Host': 'localhost', 'Content-Length': str(2 ** 64), - 'Connection': 'close', - 'Host': 'localhost' + 'Connection': 'close' }, body='X' * 1000)['status'], 400, 'Content-Length big') def test_http_header_content_length_negative(self): self.load('empty') self.assertEqual(self.post(headers={ + 'Host': 'localhost', 'Content-Length': '-100', - 'Connection': 'close', - 'Host': 'localhost' + 'Connection': 'close' }, body='X' * 1000)['status'], 400, 'Content-Length negative') def test_http_header_content_length_text(self): self.load('empty') self.assertEqual(self.post(headers={ + 'Host': 'localhost', 'Content-Length': 'blah', - 'Connection': 'close', - 'Host': 'localhost' + 'Connection': 'close' }, body='X' * 1000)['status'], 400, 'Content-Length text') def test_http_header_content_length_multiple_values(self): self.load('empty') self.assertEqual(self.post(headers={ + 'Host': 'localhost', 'Content-Length': '41, 42', - 'Connection': 'close', - 'Host': 'localhost' + 'Connection': 'close' }, body='X' * 1000)['status'], 400, 'Content-Length multiple value') def test_http_header_content_length_multiple_fields(self): self.load('empty') self.assertEqual(self.post(headers={ + 'Host': 'localhost', 'Content-Length': ['41', '42'], - 'Connection': 'close', - 'Host': 'localhost' + 'Connection': 'close' }, body='X' * 1000)['status'], 400, 'Content-Length multiple fields') if __name__ == '__main__': diff --git a/test/test_node_application.py b/test/test_node_application.py index 05b518f5..cd64fefa 100644 --- a/test/test_node_application.py +++ b/test/test_node_application.py @@ -28,7 +28,8 @@ class TestUnitNodeApplication(unit.TestUnitApplicationNode): resp = self.post(headers={ 'Host': 'localhost', 'Content-Type': 'text/html', - 'Custom-Header': 'blah' + 'Custom-Header': 'blah', + 'Connection': 'close' }, body=body) self.assertEqual(resp['status'], 200, 'status') @@ -43,10 +44,11 @@ class TestUnitNodeApplication(unit.TestUnitApplicationNode): raw_headers = headers.pop('Request-Raw-Headers') self.assertRegex(raw_headers, r'^(?:Host|localhost|Content-Type|' \ - 'text\/html|Custom-Header|blah|Content-Length|17|,)+$', - 'raw headers') + 'text\/html|Custom-Header|blah|Content-Length|17|Connection|' \ + 'close|,)+$', 'raw headers') self.assertDictEqual(headers, { + 'Connection': 'close', 'Content-Length': str(len(body)), 'Content-Type': 'text/html', 'Request-Method': 'POST', @@ -91,17 +93,17 @@ class TestUnitNodeApplication(unit.TestUnitApplicationNode): self.load('mirror') (resp, sock) = self.post(headers={ + 'Host': 'localhost', 'Connection': 'keep-alive', - 'Content-Type': 'text/html', - 'Host': 'localhost' + 'Content-Type': 'text/html' }, start=True, body='0123456789' * 500) self.assertEqual(resp['body'], '0123456789' * 500, 'keep-alive 1') resp = self.post(headers={ + 'Host': 'localhost', 'Connection': 'close', - 'Content-Type': 'text/html', - 'Host': 'localhost' + 'Content-Type': 'text/html' }, sock=sock, body='0123456789') self.assertEqual(resp['body'], '0123456789', 'keep-alive 2') @@ -142,7 +144,8 @@ class TestUnitNodeApplication(unit.TestUnitApplicationNode): resp = self.get(headers={ 'Host': 'localhost', - 'X-Remove': 'X-Header' + 'X-Remove': 'X-Header', + 'Connection': 'close' }) self.assertEqual(resp['headers']['Was-Header'], 'true', 'was header') self.assertEqual(resp['headers']['Has-Header'], 'false', 'has header') @@ -153,7 +156,8 @@ class TestUnitNodeApplication(unit.TestUnitApplicationNode): self.assertEqual(self.get(headers={ 'Host': 'localhost', - 'X-Remove': 'blah' + 'X-Remove': 'blah', + 'Connection': 'close' })['headers']['Has-Header'], 'true', 'remove header nonexisting') def test_node_application_update_header(self): @@ -194,7 +198,8 @@ class TestUnitNodeApplication(unit.TestUnitApplicationNode): self.assertEqual(self.post(headers={ 'Host': 'localhost', - 'Content-Type': 'text/html' + 'Content-Type': 'text/html', + 'Connection': 'close' }, body='callback')['status'], 200, 'promise handler request') self.assertTrue(self.waitforfiles(self.testdir + '/node/callback'), 'promise handler') @@ -205,7 +210,8 @@ class TestUnitNodeApplication(unit.TestUnitApplicationNode): self.assertEqual(self.post(headers={ 'Host': 'localhost', 'Content-Type': 'text/html', - 'X-Write-Call': '1' + 'X-Write-Call': '1', + 'Connection': 'close' }, body='callback')['status'], 200, 'promise handler request write after end') @@ -214,7 +220,8 @@ class TestUnitNodeApplication(unit.TestUnitApplicationNode): self.assertEqual(self.post(headers={ 'Host': 'localhost', - 'Content-Type': 'text/html' + 'Content-Type': 'text/html', + 'Connection': 'close' }, body='end')['status'], 200, 'promise end request') self.assertTrue(self.waitforfiles(self.testdir + '/node/callback'), 'promise end') @@ -224,7 +231,8 @@ class TestUnitNodeApplication(unit.TestUnitApplicationNode): self.post(headers={ 'Host': 'localhost', - 'Content-Type': 'text/html' + 'Content-Type': 'text/html', + 'Connection': 'close' }, body='callback1') self.assertTrue(self.waitforfiles(self.testdir + '/node/callback1'), @@ -232,7 +240,8 @@ class TestUnitNodeApplication(unit.TestUnitApplicationNode): self.post(headers={ 'Host': 'localhost', - 'Content-Type': 'text/html' + 'Content-Type': 'text/html', + 'Connection': 'close' }, body='callback2') self.assertTrue(self.waitforfiles(self.testdir + '/node/callback2'), @@ -260,12 +269,14 @@ class TestUnitNodeApplication(unit.TestUnitApplicationNode): self.assertEqual(self.get(headers={ 'Host': 'localhost', - 'X-Header': 'length' + 'X-Header': 'length', + 'Connection': 'close' })['headers']['X-Has-Header'], 'false', 'has header length') self.assertEqual(self.get(headers={ 'Host': 'localhost', - 'X-Header': 'Date' + 'X-Header': 'Date', + 'Connection': 'close' })['headers']['X-Has-Header'], 'false', 'has header date') def test_node_application_write_multiple(self): diff --git a/test/test_perl_application.py b/test/test_perl_application.py index f9acbd32..6fd0f78e 100644 --- a/test/test_perl_application.py +++ b/test/test_perl_application.py @@ -14,7 +14,8 @@ class TestUnitPerlApplication(unit.TestUnitApplicationPerl): resp = self.post(headers={ 'Host': 'localhost', 'Content-Type': 'text/html', - 'Custom-Header': 'blah' + 'Custom-Header': 'blah', + 'Connection': 'close' }, body=body) self.assertEqual(resp['status'], 200, 'status') @@ -30,6 +31,7 @@ class TestUnitPerlApplication(unit.TestUnitApplicationPerl): 'date header') self.assertDictEqual(headers, { + 'Connection': 'close', 'Content-Length': str(len(body)), 'Content-Type': 'text/html', 'Request-Method': 'POST', @@ -170,17 +172,17 @@ class TestUnitPerlApplication(unit.TestUnitApplicationPerl): self.load('variables') (resp, sock) = self.post(headers={ + 'Host': 'localhost', 'Connection': 'keep-alive', - 'Content-Type': 'text/html', - 'Host': 'localhost' + 'Content-Type': 'text/html' }, start=True, body='0123456789' * 500) self.assertEqual(resp['body'], '0123456789' * 500, 'keep-alive 1') resp = self.post(headers={ + 'Host': 'localhost', 'Connection': 'close', - 'Content-Type': 'text/html', - 'Host': 'localhost' + 'Content-Type': 'text/html' }, sock=sock, body='0123456789') self.assertEqual(resp['body'], '0123456789', 'keep-alive 2') diff --git a/test/test_php_application.py b/test/test_php_application.py index ba9c03b3..f077cd3b 100644 --- a/test/test_php_application.py +++ b/test/test_php_application.py @@ -19,7 +19,8 @@ class TestUnitPHPApplication(unit.TestUnitApplicationPHP): resp = self.post(headers={ 'Host': 'localhost', 'Content-Type': 'text/html', - 'Custom-Header': 'blah' + 'Custom-Header': 'blah', + 'Connection': 'close' }, body=body) self.assertEqual(resp['status'], 200, 'status') @@ -39,6 +40,7 @@ class TestUnitPHPApplication(unit.TestUnitApplicationPHP): headers.pop('Content-type') self.assertDictEqual(headers, { + 'Connection': 'close', 'Content-Length': str(len(body)), 'Request-Method': 'POST', 'Request-Uri': '/', @@ -96,17 +98,17 @@ class TestUnitPHPApplication(unit.TestUnitApplicationPHP): self.load('mirror') (resp, sock) = self.post(headers={ + 'Host': 'localhost', 'Connection': 'keep-alive', - 'Content-Type': 'text/html', - 'Host': 'localhost' + 'Content-Type': 'text/html' }, start=True, body='0123456789' * 500) self.assertEqual(resp['body'], '0123456789' * 500, 'keep-alive 1') resp = self.post(headers={ + 'Host': 'localhost', 'Connection': 'close', - 'Content-Type': 'text/html', - 'Host': 'localhost' + 'Content-Type': 'text/html' }, sock=sock, body='0123456789') self.assertEqual(resp['body'], '0123456789', 'keep-alive 2') diff --git a/test/test_python_application.py b/test/test_python_application.py index d37af0c4..da5d3ba2 100644 --- a/test/test_python_application.py +++ b/test/test_python_application.py @@ -15,7 +15,8 @@ class TestUnitPythonApplication(unit.TestUnitApplicationPython): resp = self.post(headers={ 'Host': 'localhost', 'Content-Type': 'text/html', - 'Custom-Header': 'blah' + 'Custom-Header': 'blah', + 'Connection': 'close' }, body=body) self.assertEqual(resp['status'], 200, 'status') @@ -31,6 +32,7 @@ class TestUnitPythonApplication(unit.TestUnitApplicationPython): 'date header') self.assertDictEqual(headers, { + 'Connection': 'close', 'Content-Length': str(len(body)), 'Content-Type': 'text/html', 'Request-Method': 'POST', @@ -90,9 +92,9 @@ class TestUnitPythonApplication(unit.TestUnitApplicationPython): self.load('ctx_iter_atexit') resp = self.post(headers={ + 'Host': 'localhost', 'Connection': 'close', - 'Content-Type': 'text/html', - 'Host': 'localhost' + 'Content-Type': 'text/html' }, body='0123456789') self.assertEqual(resp['status'], 200, 'ctx iter status') @@ -114,17 +116,17 @@ class TestUnitPythonApplication(unit.TestUnitApplicationPython): self.load('mirror') (resp, sock) = self.post(headers={ + 'Host': 'localhost', 'Connection': 'keep-alive', - 'Content-Type': 'text/html', - 'Host': 'localhost' + 'Content-Type': 'text/html' }, start=True, body='0123456789' * 500) self.assertEqual(resp['body'], '0123456789' * 500, 'keep-alive 1') resp = self.post(headers={ + 'Host': 'localhost', 'Connection': 'close', - 'Content-Type': 'text/html', - 'Host': 'localhost' + 'Content-Type': 'text/html' }, sock=sock, body='0123456789') self.assertEqual(resp['body'], '0123456789', 'keep-alive 2') @@ -138,9 +140,9 @@ class TestUnitPythonApplication(unit.TestUnitApplicationPython): for i in range(conns): (resp, sock) = self.post(headers={ + 'Host': 'localhost', 'Connection': 'keep-alive', - 'Content-Type': 'text/html', - 'Host': 'localhost' + 'Content-Type': 'text/html' }, start=True, body=body) self.assertEqual(resp['body'], body, 'keep-alive open') @@ -153,9 +155,9 @@ class TestUnitPythonApplication(unit.TestUnitApplicationPython): for i in range(conns): (resp, sock) = self.post(headers={ + 'Host': 'localhost', 'Connection': 'keep-alive', - 'Content-Type': 'text/html', - 'Host': 'localhost' + 'Content-Type': 'text/html' }, start=True, sock=socks[i], body=body) self.assertEqual(resp['body'], body, 'keep-alive request') @@ -166,9 +168,9 @@ class TestUnitPythonApplication(unit.TestUnitApplicationPython): for i in range(conns): resp = self.post(headers={ + 'Host': 'localhost', 'Connection': 'close', - 'Content-Type': 'text/html', - 'Host': 'localhost' + 'Content-Type': 'text/html' }, sock=socks[i], body=body) self.assertEqual(resp['body'], body, 'keep-alive close') @@ -183,9 +185,9 @@ class TestUnitPythonApplication(unit.TestUnitApplicationPython): body = '0123456789' (resp, sock) = self.post(headers={ + 'Host': 'localhost', 'Connection': 'keep-alive', - 'Content-Type': 'text/html', - 'Host': 'localhost' + 'Content-Type': 'text/html' }, start=True, body=body) self.assertEqual(resp['body'], body, 'reconfigure 2 keep-alive 1') @@ -193,9 +195,9 @@ class TestUnitPythonApplication(unit.TestUnitApplicationPython): self.load('empty') (resp, sock) = self.post(headers={ + 'Host': 'localhost', 'Connection': 'close', - 'Content-Type': 'text/html', - 'Host': 'localhost' + 'Content-Type': 'text/html' }, start=True, sock=sock, body=body) self.assertEqual(resp['status'], 200, 'reconfigure 2 keep-alive 2') diff --git a/test/test_ruby_application.py b/test/test_ruby_application.py index 9eed3e4a..262fc497 100644 --- a/test/test_ruby_application.py +++ b/test/test_ruby_application.py @@ -14,7 +14,8 @@ class TestUnitRubyApplication(unit.TestUnitApplicationRuby): resp = self.post(headers={ 'Host': 'localhost', 'Content-Type': 'text/html', - 'Custom-Header': 'blah' + 'Custom-Header': 'blah', + 'Connection': 'close' }, body=body) self.assertEqual(resp['status'], 200, 'status') @@ -30,6 +31,7 @@ class TestUnitRubyApplication(unit.TestUnitApplicationRuby): 'date header') self.assertDictEqual(headers, { + 'Connection': 'close', 'Content-Length': str(len(body)), 'Content-Type': 'text/html', 'Request-Method': 'POST', @@ -286,17 +288,17 @@ class TestUnitRubyApplication(unit.TestUnitApplicationRuby): self.load('mirror') (resp, sock) = self.post(headers={ + 'Host': 'localhost', 'Connection': 'keep-alive', - 'Content-Type': 'text/html', - 'Host': 'localhost' + 'Content-Type': 'text/html' }, start=True, body='0123456789' * 500) self.assertEqual(resp['body'], '0123456789' * 500, 'keep-alive 1') resp = self.post(headers={ + 'Host': 'localhost', 'Connection': 'close', - 'Content-Type': 'text/html', - 'Host': 'localhost' + 'Content-Type': 'text/html' }, sock=sock, body='0123456789') self.assertEqual(resp['body'], '0123456789', 'keep-alive 2') diff --git a/test/test_settings.py b/test/test_settings.py index d272f701..324042f9 100644 --- a/test/test_settings.py +++ b/test/test_settings.py @@ -118,6 +118,7 @@ Connection: close Host: localhost Content-Type: text/html Content-Length: %d +Connection: close """ % data_len + ('X' * data_len) @@ -140,15 +141,15 @@ Content-Length: %d self.conf({'http': { 'idle_timeout': 2 }}, 'settings') (resp, sock) = self.get(headers={ - 'Connection': 'keep-alive', - 'Host': 'localhost' + 'Host': 'localhost', + 'Connection': 'keep-alive' }, start=True) time.sleep(3) resp = self.get(headers={ - 'Connection': 'close', - 'Host': 'localhost' + 'Host': 'localhost', + 'Connection': 'close' }, sock=sock) self.assertEqual(resp['status'], 408, 'status idle timeout') diff --git a/test/test_tls.py b/test/test_tls.py index dc2f4505..2131bf30 100644 --- a/test/test_tls.py +++ b/test/test_tls.py @@ -313,8 +313,8 @@ basicConstraints = critical,CA:TRUE""" % { self.certificate() (resp, sock) = self.get(headers={ - 'Connection': 'keep-alive', - 'Host': 'localhost' + 'Host': 'localhost', + 'Connection': 'keep-alive' }, start=True) self.assertEqual(resp['status'], 200, 'initial status') @@ -334,17 +334,17 @@ basicConstraints = critical,CA:TRUE""" % { self.add_tls(application='mirror') (resp, sock) = self.post_ssl(headers={ + 'Host': 'localhost', 'Connection': 'keep-alive', - 'Content-Type': 'text/html', - 'Host': 'localhost' + 'Content-Type': 'text/html' }, start=True, body='0123456789') self.assertEqual(resp['body'], '0123456789', 'keepalive 1') resp = self.post_ssl(headers={ + 'Host': 'localhost', 'Connection': 'close', - 'Content-Type': 'text/html', - 'Host': 'localhost' + 'Content-Type': 'text/html' }, sock=sock, body='0123456789') self.assertEqual(resp['body'], '0123456789', 'keepalive 2') @@ -358,8 +358,8 @@ basicConstraints = critical,CA:TRUE""" % { self.add_tls() (resp, sock) = self.get_ssl(headers={ - 'Connection': 'keep-alive', - 'Host': 'localhost' + 'Host': 'localhost', + 'Connection': 'keep-alive' }, start=True) self.conf({ @@ -369,8 +369,8 @@ basicConstraints = critical,CA:TRUE""" % { try: resp = self.get_ssl(headers={ - 'Connection': 'close', - 'Host': 'localhost' + 'Host': 'localhost', + 'Connection': 'close' }, sock=sock) except: resp = None @@ -397,9 +397,9 @@ basicConstraints = critical,CA:TRUE""" % { self.add_tls(application='mirror') (resp, sock) = self.post_ssl(headers={ + 'Host': 'localhost', 'Connection': 'keep-alive', - 'Content-Type': 'text/html', - 'Host': 'localhost' + 'Content-Type': 'text/html' }, start=True, body='0123456789') app_id = self.findall(r'(\d+)#\d+ "mirror" application started')[0] @@ -410,9 +410,9 @@ basicConstraints = critical,CA:TRUE""" % { '#)(\d+)#\d+ "mirror" application started')) resp = self.post_ssl(headers={ + 'Host': 'localhost', 'Connection': 'close', - 'Content-Type': 'text/html', - 'Host': 'localhost' + 'Content-Type': 'text/html' }, sock=sock, body='0123456789') self.assertEqual(resp['status'], 200, 'application respawn status') -- cgit From bd77c9a4d2b0f6f609e033060a5486c0afe6b19e Mon Sep 17 00:00:00 2001 From: Andrey Zelenkov Date: Wed, 27 Feb 2019 19:43:14 +0300 Subject: Tests: read_timeout option introduced. Also, increased default select() timeout from 1s to 5s. --- test/test_python_procman.py | 2 +- test/test_settings.py | 20 +++++++++++--------- test/unit.py | 7 ++++--- 3 files changed, 16 insertions(+), 13 deletions(-) (limited to 'test') diff --git a/test/test_python_procman.py b/test/test_python_procman.py index 65268d49..2efe59c0 100644 --- a/test/test_python_procman.py +++ b/test/test_python_procman.py @@ -226,7 +226,7 @@ class TestUnitPythonProcman(unit.TestUnitApplicationPython): (resp, sock) = self.get(headers={ 'Host': 'localhost', 'Connection': 'keep-alive' - }, start=True) + }, start=True, read_timeout=1) self.assertEqual(len(self.pids_for_process()), 1, 'keepalive connection 1') diff --git a/test/test_settings.py b/test/test_settings.py index 324042f9..13bfad49 100644 --- a/test/test_settings.py +++ b/test/test_settings.py @@ -14,7 +14,7 @@ class TestUnitSettings(unit.TestUnitApplicationPython): self.conf({'http': { 'header_read_timeout': 2 }}, 'settings') (resp, sock) = self.http(b"""GET / HTTP/1.1 -""", start=True, raw=True) +""", start=True, read_timeout=1, raw=True) time.sleep(3) @@ -31,17 +31,17 @@ Connection: close self.conf({'http': { 'header_read_timeout': 4 }}, 'settings') (resp, sock) = self.http(b"""GET / HTTP/1.1 -""", start=True, raw=True, no_recv=True) +""", start=True, read_timeout=1, raw=True, no_recv=True) time.sleep(2) (resp, sock) = self.http(b"""Host: localhost -""", start=True, sock=sock, raw=True, no_recv=True) +""", start=True, sock=sock, read_timeout=1, raw=True, no_recv=True) time.sleep(2) (resp, sock) = self.http(b"""X-Blah: blah -""", start=True, sock=sock, raw=True) +""", start=True, sock=sock, read_timeout=1, raw=True) if len(resp) != 0: sock.close() @@ -66,7 +66,7 @@ Host: localhost Content-Length: 10 Connection: close -""", start=True, raw_resp=True, raw=True) +""", start=True, raw_resp=True, read_timeout=1, raw=True) time.sleep(3) @@ -84,15 +84,17 @@ Host: localhost Content-Length: 10 Connection: close -""", start=True, raw=True) +""", start=True, read_timeout=1, raw=True) time.sleep(2) - (resp, sock) = self.http(b"""012""", start=True, sock=sock, raw=True) + (resp, sock) = self.http(b"""012""", start=True, sock=sock, + read_timeout=1, raw=True) time.sleep(2) - (resp, sock) = self.http(b"""345""", start=True, sock=sock, raw=True) + (resp, sock) = self.http(b"""345""", start=True, sock=sock, + read_timeout=1, raw=True) time.sleep(2) @@ -143,7 +145,7 @@ Connection: close (resp, sock) = self.get(headers={ 'Host': 'localhost', 'Connection': 'keep-alive' - }, start=True) + }, start=True, read_timeout=1) time.sleep(3) diff --git a/test/unit.py b/test/unit.py index 80e26e0d..7a51eb20 100644 --- a/test/unit.py +++ b/test/unit.py @@ -357,7 +357,8 @@ class TestUnitHTTP(TestUnit): if 'no_recv' not in kwargs: enc = 'utf-8' if 'encoding' not in kwargs else kwargs['encoding'] - resp = self.recvall(sock).decode(enc) + read_timeout = 5 if 'read_timeout' not in kwargs else kwargs['read_timeout'] + resp = self.recvall(sock, read_timeout=read_timeout).decode(enc) if TestUnit.detailed: print('<<<', resp.encode('utf-8'), sep='\n') @@ -383,9 +384,9 @@ class TestUnitHTTP(TestUnit): def put(self, **kwargs): return self.http('PUT', **kwargs) - def recvall(self, sock, buff_size=4096): + def recvall(self, sock, read_timeout=5, buff_size=4096): data = b'' - while select.select([sock], [], [], 1)[0]: + while select.select([sock], [], [], read_timeout)[0]: try: part = sock.recv(buff_size) except: -- cgit From 8488666d606582c63f1f88a84520195cdc2ba0d7 Mon Sep 17 00:00:00 2001 From: Andrey Zelenkov Date: Wed, 27 Feb 2019 19:46:27 +0300 Subject: Tests: routing. --- test/test_routing.py | 458 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 458 insertions(+) create mode 100644 test/test_routing.py (limited to 'test') diff --git a/test/test_routing.py b/test/test_routing.py new file mode 100644 index 00000000..07097fc8 --- /dev/null +++ b/test/test_routing.py @@ -0,0 +1,458 @@ +import unittest +import unit + +class TestUnitRouting(unit.TestUnitApplicationProto): + + def setUpClass(): + unit.TestUnit().check_modules('python') + + def setUp(self): + super().setUp() + + self.conf({ + "listeners": { + "*:7080": { + "pass": "routes" + } + }, + "routes": [{ + "match": { "method": "GET" }, + "action": { "pass": "applications/empty" } + }], + "applications": { + "empty": { + "type": "python", + "processes": { "spare": 0 }, + "path": self.current_dir + '/python/empty', + "working_directory": self.current_dir + '/python/empty', + "module": "wsgi" + }, + "mirror": { + "type": "python", + "processes": { "spare": 0 }, + "path": self.current_dir + '/python/mirror', + "working_directory": self.current_dir + '/python/mirror', + "module": "wsgi" + } + } + }) + + def test_routes_match_method_positive(self): + self.assertEqual(self.get()['status'], 200, 'method positive GET') + self.assertEqual(self.post()['status'], 404, 'method positive POST') + + def test_routes_match_method_positive_many(self): + self.assertIn('success', self.conf([{ + "match": { "method": ["GET", "POST"] }, + "action": { "pass": "applications/empty" } + }], 'routes'), 'method positive many configure') + + self.assertEqual(self.get()['status'], 200, 'method positive many GET') + self.assertEqual(self.post()['status'], 200, + 'method positive many POST') + self.assertEqual(self.delete()['status'], 404, + 'method positive many DELETE') + + def test_routes_match_method_negative(self): + self.assertIn('success', self.conf([{ + "match": { "method": "!GET" }, + "action": { "pass": "applications/empty" } + }], 'routes'), 'method negative configure') + + self.assertEqual(self.get()['status'], 404, 'method negative GET') + self.assertEqual(self.post()['status'], 200, 'method negative POST') + + def test_routes_match_method_negative_many(self): + self.assertIn('success', self.conf([{ + "match": { "method": ["!GET", "!POST"] }, + "action": { "pass": "applications/empty" } + }], 'routes'), 'method negative many configure') + + self.assertEqual(self.get()['status'], 404, 'method negative many GET') + self.assertEqual(self.post()['status'], 404, + 'method negative many POST') + self.assertEqual(self.delete()['status'], 200, + 'method negative many DELETE') + + def test_routes_match_method_wildcard_left(self): + self.assertIn('success', self.conf([{ + "match": { "method": "*ET" }, + "action": { "pass": "applications/empty" } + }], 'routes'), 'method wildcard left configure') + + self.assertEqual(self.get()['status'], 200, 'method wildcard left GET') + self.assertEqual(self.post()['status'], 404, + 'method wildcard left POST') + + def test_routes_match_method_wildcard_right(self): + self.assertIn('success', self.conf([{ + "match": { "method": "GE*" }, + "action": { "pass": "applications/empty"} + }], 'routes'), 'method wildcard right configure') + + self.assertEqual(self.get()['status'], 200, + 'method wildcard right GET') + self.assertEqual(self.post()['status'], 404, + 'method wildcard right POST') + + def test_routes_match_method_wildcard_left_right(self): + self.assertIn('success', self.conf([{ + "match": { "method": "*GET*" }, + "action": { "pass": "applications/empty" } + }], 'routes'), 'method wildcard left right configure') + + self.assertEqual(self.get()['status'], 200, + 'method wildcard right GET') + self.assertEqual(self.post()['status'], 404, + 'method wildcard right POST') + + def test_routes_match_method_wildcard(self): + self.assertIn('success', self.conf([{ + "match": { "method": "*" }, + "action": { "pass": "applications/empty" } + }], 'routes'), 'method wildcard configure') + + self.assertEqual(self.get()['status'], 200, 'method wildcard') + + def test_routes_match_method_case_insensitive(self): + self.assertIn('success', self.conf([{ + "match": { "method": "get" }, + "action": { "pass": "applications/empty" } + }], 'routes'), 'method case insensitive configure') + + self.assertEqual(self.get()['status'], 200, 'method case insensitive') + + def test_routes_absent(self): + self.conf({ + "listeners": { + "*:7081": { + "pass": "applications/empty" + } + }, + "applications": { + "empty": { + "type": "python", + "processes": { "spare": 0 }, + "path": self.current_dir + '/python/empty', + "working_directory": self.current_dir + '/python/empty', + "module": "wsgi" + } + } + }) + + self.assertEqual(self.get(port=7081)['status'], 200, 'routes absent') + + def test_routes_pass_invalid(self): + self.assertIn('error', self.conf({ "pass": "routes/blah" }, + 'listeners/*:7080'), 'routes invalid') + + def test_route_empty(self): + self.assertIn('success', self.conf({ + "listeners": { + "*:7080": { + "pass": "routes/main" + } + }, + "routes": {"main": []}, + "applications": { + "empty": { + "type": "python", + "processes": { "spare": 0 }, + "path": self.current_dir + '/python/empty', + "working_directory": self.current_dir + '/python/empty', + "module": "wsgi" + }, + "mirror": { + "type": "python", + "processes": { "spare": 0 }, + "path": self.current_dir + '/python/mirror', + "working_directory": self.current_dir + '/python/mirror', + "module": "wsgi" + } + } + }), 'route empty configure') + + self.assertEqual(self.get()['status'], 404, 'route empty') + + def test_routes_route_empty(self): + self.assertIn('success', self.conf({}, 'listeners'), + 'routes empty listeners configure') + + self.assertIn('success', self.conf({}, 'routes'), + 'routes empty configure') + + def test_routes_route_match_absent(self): + self.assertIn('success', self.conf([{ + "action": { "pass": "applications/empty" } + }], 'routes'), 'route match absent configure') + + self.assertEqual(self.get()['status'], 200, 'route match absent') + + def test_routes_route_action_absent(self): + self.skip_alerts.append(r'failed to apply new conf') + + self.assertIn('error', self.conf([{ + "match": { "method": "GET" } + }], 'routes'), 'route pass absent configure') + + def test_routes_route_pass_absent(self): + self.skip_alerts.append(r'failed to apply new conf') + + self.assertIn('error', self.conf([{ + "match": { "method": "GET" }, + "action": {} + }], 'routes'), 'route pass absent configure') + + def test_routes_rules_two(self): + self.assertIn('success', self.conf([{ + "match": { "method": "GET" }, + "action": { "pass": "applications/empty" } + }, + { + "match": { "method": "POST" }, + "action": { "pass": "applications/mirror" } + }], 'routes'), 'rules two configure') + + self.assertEqual(self.get()['status'], 200, 'rules two match first') + self.assertEqual(self.post(headers={ + 'Host': 'localhost', + 'Content-Type': 'text/html', + 'Connection': 'close' + }, body='X')['status'], 200, 'rules two match second') + + def test_routes_two(self): + self.assertIn('success', self.conf({ + "listeners": { + "*:7080": { + "pass": "routes/first" + } + }, + "routes": { + "first": [{ + "match": { "method": "GET" }, + "action": { "pass": "routes/second" } + }], + "second": [{ + "match": { "host": "localhost" }, + "action": { "pass": "applications/empty" } + }], + }, + "applications": { + "empty": { + "type": "python", + "processes": { "spare": 0 }, + "path": self.current_dir + '/python/empty', + "working_directory": self.current_dir + '/python/empty', + "module": "wsgi" + } + } + }), 'routes two configure') + + self.assertEqual(self.get()['status'], 200, 'routes two') + + def test_routes_match_host_positive(self): + self.assertIn('success', self.conf([{ + "match": { "host": "localhost" }, + "action": { "pass": "applications/empty" } + }], 'routes'), 'match host positive configure') + + self.assertEqual(self.get()['status'], 200, + 'match host positive localhost') + + self.assertEqual(self.get(headers={'Connection': 'close'})['status'], + 404, 'match host positive empty') + + self.assertEqual(self.get(headers={ + 'Host': 'localhost.', + 'Connection': 'close' + })['status'], 200, 'match host positive trailing dot') + + self.assertEqual(self.get(headers={ + 'Host': 'www.localhost', + 'Connection': 'close' + })['status'], 404, 'match host positive www.localhost') + + self.assertEqual(self.get(headers={ + 'Host': 'localhost1', + 'Connection': 'close' + })['status'], 404, 'match host positive localhost1') + + self.assertEqual(self.get(headers={ + 'Host': 'example.com', + 'Connection': 'close' + })['status'], 404, 'match host positive example.com') + + def test_routes_match_host_ipv4(self): + self.assertIn('success', self.conf([{ + "match": { "host": "127.0.0.1" }, + "action": { "pass": "applications/empty" } + }], 'routes'), 'match host ipv4 configure') + + self.assertEqual(self.get(headers={ + 'Host': '127.0.0.1', + 'Connection': 'close' + })['status'], 200, 'match host ipv4') + + def test_routes_match_host_ipv6(self): + self.assertIn('success', self.conf([{ + "match": { "host": "[::1]" }, + "action": { "pass": "applications/empty" } + }], 'routes'), 'match host ipv6 configure') + + self.assertEqual(self.get(headers={ + 'Host': '[::1]', + 'Connection': 'close' + })['status'], 200, 'match host ipv6') + + self.assertEqual(self.get(headers={ + 'Host': '[::1]:7080', + 'Connection': 'close' + })['status'], 200, 'match host ipv6 port') + + def test_routes_match_host_positive_many(self): + self.assertIn('success', self.conf([{ + "match": { "host": ["localhost", "example.com"] }, + "action": { "pass": "applications/empty" } + }], 'routes'), 'match host positive many configure') + + self.assertEqual(self.get()['status'], 200, + 'match host positive many localhost') + + self.assertEqual(self.get(headers={ + 'Host': 'example.com', + 'Connection': 'close' + })['status'], 200, 'match host positive many example.com') + + def test_routes_match_host_positive_and_negative(self): + self.assertIn('success', self.conf([{ + "match": { "host": ["*example.com", "!www.example.com"] }, + "action": { "pass": "applications/empty" } + }], 'routes'), 'match host positive and negative configure') + + self.assertEqual(self.get()['status'], 404, + 'match host positive and negative localhost') + + self.assertEqual(self.get(headers={ + 'Host': 'example.com', + 'Connection': 'close' + })['status'], 200, 'match host positive and negative example.com') + + self.assertEqual(self.get(headers={ + 'Host': 'www.example.com', + 'Connection': 'close' + })['status'], 404, 'match host positive and negative www.example.com') + + self.assertEqual(self.get(headers={ + 'Host': '!www.example.com', + 'Connection': 'close' + })['status'], 200, 'match host positive and negative !www.example.com') + + def test_routes_match_host_positive_and_negative_wildcard(self): + self.assertIn('success', self.conf([{ + "match": { "host": ["*example*", "!www.example*"] }, + "action": { "pass": "applications/empty" } + }], 'routes'), 'match host positive and negative wildcard configure') + + self.assertEqual(self.get(headers={ + 'Host': 'example.com', + 'Connection': 'close' + })['status'], 200, + 'match host positive and negative wildcard example.com') + + self.assertEqual(self.get(headers={ + 'Host': 'www.example.com', + 'Connection': 'close' + })['status'], 404, + 'match host positive and negative wildcard www.example.com') + + def test_routes_match_host_case_insensitive(self): + self.assertIn('success', self.conf([{ + "match": { "host": "Example.com" }, + "action": { "pass": "applications/empty" } + }], 'routes'), 'host case insensitive configure') + + self.assertEqual(self.get(headers={ + 'Host': 'example.com', + 'Connection': 'close' + })['status'], 200, 'host case insensitive example.com') + + self.assertEqual(self.get(headers={ + 'Host': 'EXAMPLE.COM', + 'Connection': 'close' + })['status'], 200, 'host case insensitive EXAMPLE.COM') + + def test_routes_match_host_port(self): + self.assertIn('success', self.conf([{ + "match": { "host": "example.com" }, + "action": { "pass": "applications/empty" } + }], 'routes'), 'match host port configure') + + self.assertEqual(self.get(headers={ + 'Host': 'example.com:7080', + 'Connection': 'close' + })['status'], 200, 'match host port') + + def test_routes_match_uri_positive(self): + self.assertIn('success', self.conf([{ + "match": { "uri": "/" }, + "action": { "pass": "applications/empty" } + }], 'routes'), 'match uri positive configure') + + self.assertEqual(self.get()['status'], 200, 'match uri positive') + self.assertEqual(self.get(url='/blah')['status'], 404, + 'match uri positive blah') + self.assertEqual(self.get(url='/#blah')['status'], 200, + 'match uri positive #blah') + self.assertEqual(self.get(url='/?var')['status'], 200, + 'match uri params') + self.assertEqual(self.get(url='//')['status'], 200, + 'match uri adjacent slashes') + self.assertEqual(self.get(url='/blah/../')['status'], 200, + 'match uri relative path') + self.assertEqual(self.get(url='/./')['status'], 200, + 'match uri relative path') + + def test_routes_match_uri_case_sensitive(self): + self.assertIn('success', self.conf([{ + "match": { "uri": "/BLAH" }, + "action": { "pass": "applications/empty" } + }], 'routes'), 'match uri case sensitive configure') + + self.assertEqual(self.get(url='/blah')['status'], 404, + 'match uri case sensitive blah') + self.assertEqual(self.get(url='/BlaH')['status'], 404, + 'match uri case sensitive BlaH') + self.assertEqual(self.get(url='/BLAH')['status'], 200, + 'match uri case sensitive BLAH') + + def test_routes_match_uri_normalize(self): + self.assertIn('success', self.conf([{ + "match": { "uri": "/blah" }, + "action": { "pass": "applications/empty" } + }], 'routes'), 'match uri normalize configure') + + self.assertEqual(self.get(url='/%62%6c%61%68')['status'], 200, + 'match uri normalize') + + def test_routes_match_rules(self): + self.assertIn('success', self.conf([{ + "match": { + "method": "GET", + "host": "localhost", + "uri": "/" + }, + "action": { "pass": "applications/empty" } + }], 'routes'), 'routes match rules configure') + + self.assertEqual(self.get()['status'], 200, 'routes match rules') + + def test_routes_loop(self): + self.assertIn('success', self.conf([{ + "match": { "uri": "/" }, + "action": { "pass": "routes" } + }], 'routes'), 'routes loop configure') + + self.assertEqual(self.get()['status'], 500, 'routes loop') + +if __name__ == '__main__': + TestUnitRouting.main() -- cgit From 4b925865303de419af13f046eb4e3ebeb53a8a25 Mon Sep 17 00:00:00 2001 From: Andrey Zelenkov Date: Wed, 27 Feb 2019 20:41:30 +0300 Subject: Tests: "Host" header tests. --- test/python/host/wsgi.py | 7 +++ test/test_http_header.py | 147 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 154 insertions(+) create mode 100644 test/python/host/wsgi.py (limited to 'test') diff --git a/test/python/host/wsgi.py b/test/python/host/wsgi.py new file mode 100644 index 00000000..db7de306 --- /dev/null +++ b/test/python/host/wsgi.py @@ -0,0 +1,7 @@ +def application(env, start_response): + start_response('200', [ + ('Content-Length', '0'), + ('X-Server-Name', env.get('SERVER_NAME')), + ('X-Http-Host', str(env.get('HTTP_HOST'))) + ]) + return [] diff --git a/test/test_http_header.py b/test/test_http_header.py index a7638b8d..f2294371 100644 --- a/test/test_http_header.py +++ b/test/test_http_header.py @@ -212,5 +212,152 @@ Connection: close 'Connection': 'close' }, body='X' * 1000)['status'], 400, 'Content-Length multiple fields') + def test_http_header_host_absent(self): + self.load('host') + + resp = self.get(headers={'Connection': 'close'}) + + self.assertEqual(resp['status'], 200, 'Host absent status') + self.assertNotEqual(resp['headers']['X-Server-Name'], '', + 'Host absent SERVER_NAME') + + def test_http_header_host_empty(self): + self.load('host') + + resp = self.get(headers={ + 'Host': '', + 'Connection': 'close' + }) + + self.assertEqual(resp['status'], 200, 'Host empty status') + self.assertNotEqual(resp['headers']['X-Server-Name'], '', + 'Host empty SERVER_NAME') + + def test_http_header_host_big(self): + self.load('empty') + + self.assertEqual(self.get(headers={ + 'Host': 'X' * 10000, + 'Connection': 'close' + })['status'], 431, 'Host big') + + def test_http_header_host_port(self): + self.load('host') + + resp = self.get(headers={ + 'Host': 'exmaple.com:7080', + 'Connection': 'close' + }) + + self.assertEqual(resp['status'], 200, 'Host port status') + self.assertEqual(resp['headers']['X-Server-Name'], 'exmaple.com', + 'Host port SERVER_NAME') + self.assertEqual(resp['headers']['X-Http-Host'], 'exmaple.com:7080', + 'Host port HTTP_HOST') + + def test_http_header_host_port_empty(self): + self.load('host') + + resp = self.get(headers={ + 'Host': 'exmaple.com:', + 'Connection': 'close' + }) + + self.assertEqual(resp['status'], 200, 'Host port empty status') + self.assertEqual(resp['headers']['X-Server-Name'], 'exmaple.com', + 'Host port empty SERVER_NAME') + self.assertEqual(resp['headers']['X-Http-Host'], 'exmaple.com:', + 'Host port empty HTTP_HOST') + + def test_http_header_host_literal(self): + self.load('host') + + resp = self.get(headers={ + 'Host': '127.0.0.1', + 'Connection': 'close' + }) + + self.assertEqual(resp['status'], 200, 'Host literal status') + self.assertEqual(resp['headers']['X-Server-Name'], '127.0.0.1', + 'Host literal SERVER_NAME') + + def test_http_header_host_literal_ipv6(self): + self.load('host') + + resp = self.get(headers={ + 'Host': '[::1]:7080', + 'Connection': 'close' + }) + + self.assertEqual(resp['status'], 200, 'Host literal ipv6 status') + self.assertEqual(resp['headers']['X-Server-Name'], '[::1]', + 'Host literal ipv6 SERVER_NAME') + self.assertEqual(resp['headers']['X-Http-Host'], '[::1]:7080', + 'Host literal ipv6 HTTP_HOST') + + def test_http_header_host_trailing_period(self): + self.load('host') + + resp = self.get(headers={ + 'Host': '127.0.0.1.', + 'Connection': 'close' + }) + + self.assertEqual(resp['status'], 200, 'Host trailing period status') + self.assertEqual(resp['headers']['X-Server-Name'], '127.0.0.1', + 'Host trailing period SERVER_NAME') + self.assertEqual(resp['headers']['X-Http-Host'], '127.0.0.1.', + 'Host trailing period HTTP_HOST') + + def test_http_header_host_trailing_period_2(self): + self.load('host') + + resp = self.get(headers={ + 'Host': 'EXAMPLE.COM.', + 'Connection': 'close' + }) + + self.assertEqual(resp['status'], 200, 'Host trailing period 2 status') + self.assertEqual(resp['headers']['X-Server-Name'], 'example.com', + 'Host trailing period 2 SERVER_NAME') + self.assertEqual(resp['headers']['X-Http-Host'], 'EXAMPLE.COM.', + 'Host trailing period 2 HTTP_HOST') + + def test_http_header_host_case_insensitive(self): + self.load('host') + + resp = self.get(headers={ + 'Host': 'EXAMPLE.COM', + 'Connection': 'close' + }) + + self.assertEqual(resp['status'], 200, 'Host case insensitive') + self.assertEqual(resp['headers']['X-Server-Name'], 'example.com', + 'Host case insensitive SERVER_NAME') + + def test_http_header_host_double_dot(self): + self.load('empty') + + self.assertEqual(self.get(headers={ + 'Host': '127.0.0..1', + 'Connection': 'close' + })['status'], 400, 'Host double dot') + + def test_http_header_host_slash(self): + self.load('empty') + + self.assertEqual(self.get(headers={ + 'Host': '/localhost', + 'Connection': 'close' + })['status'], 400, 'Host slash') + + def test_http_header_host_multiple_fields(self): + self.load('empty') + + self.assertEqual(self.get(headers={ + 'Host': ['localhost', 'example.com'], + 'Connection': 'close' + })['status'], 400, 'Host multiple fields') + if __name__ == '__main__': TestUnitHTTPHeader.main() -- cgit From 5bfdebb9e4161a689113d73775498949a09d7fb5 Mon Sep 17 00:00:00 2001 From: Max Romanov Date: Thu, 28 Feb 2019 18:02:42 +0300 Subject: Introducing Java Servlet Container beta. --- test/java/content_type/app.java | 89 ++++ test/java/cookies/app.java | 30 ++ test/java/empty/app.java | 18 + test/java/filter/app.java | 54 +++ test/java/forward/app.java | 138 ++++++ test/java/forward/index.html | 1 + test/java/forward/web.xml | 38 ++ test/java/get_header/app.java | 21 + test/java/get_header_names/app.java | 27 ++ test/java/get_headers/app.java | 27 ++ test/java/get_params/app.java | 50 ++ test/java/header/app.java | 34 ++ test/java/header_date/app.java | 22 + test/java/header_int/app.java | 22 + test/java/include/app.java | 136 ++++++ test/java/include/index.html | 1 + test/java/include/web.xml | 37 ++ test/java/jsp/index.jsp | 2 + test/java/mirror/app.java | 37 ++ test/java/path_translation/app.java | 56 +++ test/java/path_translation/index.html | 1 + test/java/post_params/app.java | 22 + test/java/query_string/app.java | 20 + test/java/request_listeners/app.java | 79 ++++ test/java/session/app.java | 30 ++ test/java/session_inactive/app.java | 27 ++ test/java/session_invalidate/app.java | 23 + test/java/session_listeners/app.java | 80 ++++ test/java/session_listeners/web.xml | 14 + test/java/url_pattern/app.java | 39 ++ test/java/url_pattern/web.xml | 75 +++ test/java/welcome_files/app.java | 67 +++ test/java/welcome_files/dir1/index.txt | 1 + test/java/welcome_files/dir2/default.jsp | 3 + test/java/welcome_files/dir2/index.html | 1 + test/java/welcome_files/dir3/index.txt | 1 + test/java/welcome_files/dir4/index.html | 1 + test/java/welcome_files/index.htm | 1 + test/java/welcome_files/web.xml | 27 ++ test/test_java_application.py | 753 +++++++++++++++++++++++++++++++ test/unit.py | 66 +++ 41 files changed, 2171 insertions(+) create mode 100644 test/java/content_type/app.java create mode 100644 test/java/cookies/app.java create mode 100644 test/java/empty/app.java create mode 100644 test/java/filter/app.java create mode 100644 test/java/forward/app.java create mode 100644 test/java/forward/index.html create mode 100644 test/java/forward/web.xml create mode 100644 test/java/get_header/app.java create mode 100644 test/java/get_header_names/app.java create mode 100644 test/java/get_headers/app.java create mode 100644 test/java/get_params/app.java create mode 100644 test/java/header/app.java create mode 100644 test/java/header_date/app.java create mode 100644 test/java/header_int/app.java create mode 100644 test/java/include/app.java create mode 100644 test/java/include/index.html create mode 100644 test/java/include/web.xml create mode 100644 test/java/jsp/index.jsp create mode 100644 test/java/mirror/app.java create mode 100644 test/java/path_translation/app.java create mode 100644 test/java/path_translation/index.html create mode 100644 test/java/post_params/app.java create mode 100644 test/java/query_string/app.java create mode 100644 test/java/request_listeners/app.java create mode 100644 test/java/session/app.java create mode 100644 test/java/session_inactive/app.java create mode 100644 test/java/session_invalidate/app.java create mode 100644 test/java/session_listeners/app.java create mode 100644 test/java/session_listeners/web.xml create mode 100644 test/java/url_pattern/app.java create mode 100644 test/java/url_pattern/web.xml create mode 100644 test/java/welcome_files/app.java create mode 100644 test/java/welcome_files/dir1/index.txt create mode 100644 test/java/welcome_files/dir2/default.jsp create mode 100644 test/java/welcome_files/dir2/index.html create mode 100644 test/java/welcome_files/dir3/index.txt create mode 100644 test/java/welcome_files/dir4/index.html create mode 100644 test/java/welcome_files/index.htm create mode 100644 test/java/welcome_files/web.xml create mode 100644 test/test_java_application.py (limited to 'test') diff --git a/test/java/content_type/app.java b/test/java/content_type/app.java new file mode 100644 index 00000000..7d8a7418 --- /dev/null +++ b/test/java/content_type/app.java @@ -0,0 +1,89 @@ + +import java.io.IOException; +import java.io.PrintWriter; + +import javax.servlet.ServletConfig; +import javax.servlet.ServletException; +import javax.servlet.annotation.WebServlet; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +@WebServlet("/") +public class app extends HttpServlet +{ + @Override + public void doGet(HttpServletRequest request, HttpServletResponse response) + throws IOException, ServletException + { + if (request.getServletPath().equals("/1")) { + response.setContentType("text/plain;charset=utf-8"); + response.setHeader("X-Character-Encoding", response.getCharacterEncoding()); + response.setHeader("X-Content-Type", response.getContentType()); + return; + } + + if (request.getServletPath().equals("/2")) { + response.setContentType("text/plain"); + response.setHeader("X-Character-Encoding", response.getCharacterEncoding()); + response.setHeader("X-Content-Type", response.getContentType()); + return; + } + + if (request.getServletPath().equals("/3")) { + response.setContentType("text/plain;charset=utf-8"); + response.setCharacterEncoding("windows-1251"); + response.setHeader("X-Character-Encoding", response.getCharacterEncoding()); + response.setHeader("X-Content-Type", response.getContentType()); + return; + } + + if (request.getServletPath().equals("/4")) { + response.setCharacterEncoding("windows-1251"); + response.setContentType("text/plain"); + response.setHeader("X-Character-Encoding", response.getCharacterEncoding()); + response.setHeader("X-Content-Type", response.getContentType()); + return; + } + + if (request.getServletPath().equals("/5")) { + response.setContentType("text/plain;charset=utf-8"); + response.setCharacterEncoding(null); + response.setHeader("X-Character-Encoding", response.getCharacterEncoding()); + response.setHeader("X-Content-Type", response.getContentType()); + return; + } + + if (request.getServletPath().equals("/6")) { + response.setContentType("text/plain;charset=utf-8"); + response.setContentType(null); + response.setHeader("X-Character-Encoding", response.getCharacterEncoding()); + response.setHeader("X-Content-Type", response.getContentType()); + return; + } + + if (request.getServletPath().equals("/7")) { + response.setContentType("text/plain;charset=utf-8"); + + PrintWriter out = response.getWriter(); + + response.setCharacterEncoding("windows-1251"); + response.setHeader("X-Character-Encoding", response.getCharacterEncoding()); + response.setHeader("X-Content-Type", response.getContentType()); + return; + } + + if (request.getServletPath().equals("/8")) { + response.setContentType("text/plain;charset=utf-8"); + + PrintWriter out = response.getWriter(); + + response.setContentType("text/html;charset=windows-1251"); + response.setHeader("X-Character-Encoding", response.getCharacterEncoding()); + response.setHeader("X-Content-Type", response.getContentType()); + return; + } + + response.sendError(404); + } +} diff --git a/test/java/cookies/app.java b/test/java/cookies/app.java new file mode 100644 index 00000000..13cea6d1 --- /dev/null +++ b/test/java/cookies/app.java @@ -0,0 +1,30 @@ + +import java.io.IOException; + +import javax.servlet.ServletException; +import javax.servlet.annotation.WebServlet; +import javax.servlet.http.Cookie; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +@WebServlet(urlPatterns = "/") +public class app extends HttpServlet +{ + @Override + public void doGet(HttpServletRequest request, HttpServletResponse response) + throws IOException, ServletException + { + Cookie[] cookies = request.getCookies(); + if (cookies != null) { + for (Cookie c : cookies) { + if (c.getName().equals("var1")) { + response.addHeader("X-Cookie-1", c.getValue()); + } + if (c.getName().equals("var2")) { + response.addHeader("X-Cookie-2", c.getValue()); + } + } + } + } +} diff --git a/test/java/empty/app.java b/test/java/empty/app.java new file mode 100644 index 00000000..b0fca631 --- /dev/null +++ b/test/java/empty/app.java @@ -0,0 +1,18 @@ + +import java.io.IOException; + +import javax.servlet.ServletConfig; +import javax.servlet.ServletException; +import javax.servlet.annotation.WebServlet; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +@WebServlet("/") +public class app extends HttpServlet +{ + @Override + public void doGet(HttpServletRequest request, HttpServletResponse response) + throws IOException, ServletException + { } +} diff --git a/test/java/filter/app.java b/test/java/filter/app.java new file mode 100644 index 00000000..a5da3997 --- /dev/null +++ b/test/java/filter/app.java @@ -0,0 +1,54 @@ + +import java.io.IOException; + +import javax.servlet.ServletException; +import javax.servlet.annotation.WebServlet; +import javax.servlet.annotation.WebFilter; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.Filter; +import javax.servlet.FilterChain; +import javax.servlet.FilterConfig; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; + +@WebServlet(urlPatterns = "/") +public class app extends HttpServlet +{ + @WebFilter(urlPatterns = "") + public static class filter implements Filter + { + @Override + public void init(FilterConfig filterConfig) + { + } + + @Override + public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) + throws IOException, ServletException + { + response.getOutputStream().println("Extra Info"); + response.setCharacterEncoding("utf-8"); + + ((HttpServletResponse) response).addHeader("X-Filter-Before", "1"); + + chain.doFilter(request, response); + + ((HttpServletResponse) response).setHeader("X-Filter-After", "1"); + } + + @Override + public void destroy() + { + } + } + + @Override + public void doGet(HttpServletRequest request, HttpServletResponse response) + throws IOException, ServletException + { + response.getOutputStream().println("This is servlet response"); + response.setHeader("X-Filter-After", "0"); + } +} diff --git a/test/java/forward/app.java b/test/java/forward/app.java new file mode 100644 index 00000000..0dea17d6 --- /dev/null +++ b/test/java/forward/app.java @@ -0,0 +1,138 @@ + +import java.io.IOException; +import java.io.PrintWriter; + +import java.util.Map; + +import javax.servlet.DispatcherType; +import javax.servlet.RequestDispatcher; +import javax.servlet.ServletConfig; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletRequestWrapper; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpServletResponseWrapper; + +public class app extends HttpServlet +{ + private String id; + + private class RequestWrapper extends HttpServletRequestWrapper + { + public RequestWrapper(HttpServletRequest r) + { + super(r); + } + } + + private class ResponseWrapper extends HttpServletResponseWrapper + { + public ResponseWrapper(HttpServletResponse r) + { + super(r); + } + } + + @Override + public void init(ServletConfig sc) + throws ServletException + { + id = sc.getInitParameter("id"); + } + + private RequestDispatcher getRequestDispatcher(HttpServletRequest request, String str) + { + String disp = request.getParameter("disp"); + + if (disp != null && disp.equals("ctx")) { + return request.getServletContext().getRequestDispatcher(str); + } + + if (disp != null && disp.equals("name")) { + return request.getServletContext().getNamedDispatcher(str); + } + + if (disp == null || disp.equals("req")) { + return request.getRequestDispatcher(str); + } + + return null; + } + + @Override + public void doGet(HttpServletRequest request, HttpServletResponse response) + throws IOException, ServletException + { + String dtype = "" + request.getDispatcherType(); + + response.addHeader("X-" + dtype + "-Id", id); + response.addHeader("X-" + dtype + "-Request-URI", "" + request.getRequestURI()); + response.addHeader("X-" + dtype + "-Servlet-Path", "" + request.getServletPath()); + response.addHeader("X-" + dtype + "-Path-Info", "" + request.getPathInfo()); + response.addHeader("X-" + dtype + "-Query-String", "" + request.getQueryString()); + response.addHeader("X-" + dtype + "-Dispatcher-Type", "" + request.getDispatcherType()); + + response.setContentType("text/plain; charset=utf-8"); + + Map pmap = request.getParameterMap(); + + for (Map.Entry p : pmap.entrySet()) { + response.addHeader("X-" + dtype + "-Param-" + p.getKey(), "" + String.join(",", p.getValue())); + } + + PrintWriter out = response.getWriter(); + + if (id.equals("fwd")) { + String uri = request.getParameter("uri"); + + if (uri != null && request.getDispatcherType() != DispatcherType.FORWARD) { + response.addHeader("X-Forward-To", "" + uri); + + out.println("Before forwarding."); + + RequestDispatcher d = getRequestDispatcher(request, uri); + + if (d == null) { + out.println("Dispatcher is null"); + return; + } + + try { + d.forward(new RequestWrapper(request), new ResponseWrapper(response)); + } catch(Exception e) { + response.addHeader("X-Exception", "" + e); + } + + response.addHeader("X-After-Forwarding", "you-should-not-see-this"); + + out.println("After forwarding."); + + return; + } + } + + if (id.equals("data")) { + response.addHeader("X-" + RequestDispatcher.FORWARD_REQUEST_URI, "" + request.getAttribute(RequestDispatcher.FORWARD_REQUEST_URI)); + response.addHeader("X-" + RequestDispatcher.FORWARD_CONTEXT_PATH, "" + request.getAttribute(RequestDispatcher.FORWARD_CONTEXT_PATH)); + response.addHeader("X-" + RequestDispatcher.FORWARD_SERVLET_PATH, "" + request.getAttribute(RequestDispatcher.FORWARD_SERVLET_PATH)); + response.addHeader("X-" + RequestDispatcher.FORWARD_PATH_INFO, "" + request.getAttribute(RequestDispatcher.FORWARD_PATH_INFO)); + response.addHeader("X-" + RequestDispatcher.FORWARD_QUERY_STRING, "" + request.getAttribute(RequestDispatcher.FORWARD_QUERY_STRING)); + + out.println("app.doGet(): #" + this + ", " + id); + out.println("RequestURI: " + request.getRequestURI()); + out.println("ServletPath: " + request.getServletPath()); + out.println("PathInfo: " + request.getPathInfo()); + out.println("DispType: " + request.getDispatcherType()); + out.println("QueryString: " + request.getQueryString()); + + for (Map.Entry p : pmap.entrySet()) { + out.println("- " + p.getKey() + "=" + String.join(",", p.getValue())); + } + + return; + } + + response.sendError(404); + } +} diff --git a/test/java/forward/index.html b/test/java/forward/index.html new file mode 100644 index 00000000..4f5a6379 --- /dev/null +++ b/test/java/forward/index.html @@ -0,0 +1 @@ +This is index.html. diff --git a/test/java/forward/web.xml b/test/java/forward/web.xml new file mode 100644 index 00000000..994adb37 --- /dev/null +++ b/test/java/forward/web.xml @@ -0,0 +1,38 @@ + + + + + + fwd + app + idfwd + + + + fwd + /fwd/* + + + + + data + app + iddata + + + + data + /data/* + + + + data + /WEB-INF/index.html + /index.html + + + + diff --git a/test/java/get_header/app.java b/test/java/get_header/app.java new file mode 100644 index 00000000..c981835d --- /dev/null +++ b/test/java/get_header/app.java @@ -0,0 +1,21 @@ + +import java.io.IOException; +import java.io.PrintWriter; + +import javax.servlet.ServletConfig; +import javax.servlet.ServletException; +import javax.servlet.annotation.WebServlet; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +@WebServlet("/") +public class app extends HttpServlet +{ + @Override + public void doGet(HttpServletRequest request, HttpServletResponse response) + throws IOException, ServletException + { + response.addHeader("X-Reply", request.getHeader("X-Header")); + } +} diff --git a/test/java/get_header_names/app.java b/test/java/get_header_names/app.java new file mode 100644 index 00000000..cd2f3097 --- /dev/null +++ b/test/java/get_header_names/app.java @@ -0,0 +1,27 @@ + +import java.io.IOException; +import java.io.PrintWriter; +import java.util.Enumeration; + +import javax.servlet.ServletConfig; +import javax.servlet.ServletException; +import javax.servlet.annotation.WebServlet; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +@WebServlet("/") +public class app extends HttpServlet +{ + @Override + public void doGet(HttpServletRequest request, HttpServletResponse response) + throws IOException, ServletException + { + Enumeration header_names = request.getHeaderNames(); + + for (int i = 0; header_names.hasMoreElements(); i++) { + response.addHeader("X-Reply-" + Integer.toString(i), + header_names.nextElement()); + } + } +} diff --git a/test/java/get_headers/app.java b/test/java/get_headers/app.java new file mode 100644 index 00000000..f2930a61 --- /dev/null +++ b/test/java/get_headers/app.java @@ -0,0 +1,27 @@ + +import java.io.IOException; +import java.io.PrintWriter; +import java.util.Enumeration; + +import javax.servlet.ServletConfig; +import javax.servlet.ServletException; +import javax.servlet.annotation.WebServlet; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +@WebServlet("/") +public class app extends HttpServlet +{ + @Override + public void doGet(HttpServletRequest request, HttpServletResponse response) + throws IOException, ServletException + { + Enumeration headers = request.getHeaders("X-Header"); + + for (int i = 0; headers.hasMoreElements(); i++) { + response.addHeader("X-Reply-" + Integer.toString(i), + headers.nextElement()); + } + } +} diff --git a/test/java/get_params/app.java b/test/java/get_params/app.java new file mode 100644 index 00000000..1965ae2a --- /dev/null +++ b/test/java/get_params/app.java @@ -0,0 +1,50 @@ + +import java.io.IOException; + +import java.util.Enumeration; +import java.util.Map; + +import javax.servlet.ServletException; +import javax.servlet.annotation.WebServlet; +import javax.servlet.http.Cookie; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +@WebServlet(urlPatterns = "/") +public class app extends HttpServlet +{ + @Override + public void doGet(HttpServletRequest request, HttpServletResponse response) + throws IOException, ServletException + { + response.addHeader("X-Var-1", request.getParameter("var1")); + response.addHeader("X-Var-2", "" + (request.getParameter("var2") != null)); + response.addHeader("X-Var-3", "" + (request.getParameter("var3") != null)); + response.addHeader("X-Var-4", request.getParameter("var4")); + + Enumeration parameter_names = request.getParameterNames(); + + String names = ""; + for (int i = 0; parameter_names.hasMoreElements(); i++) { + names = names.concat(parameter_names.nextElement() + " "); + } + response.addHeader("X-Param-Names", names); + + String[] parameter_values = request.getParameterValues("var4"); + + String values = ""; + for (int i = 0; i < parameter_values.length; i++) { + values = values.concat(parameter_values[i] + " "); + } + response.addHeader("X-Param-Values", values); + + Map parameter_map = request.getParameterMap(); + + String map = ""; + for (Map.Entry p : parameter_map.entrySet()) { + map = map.concat(p.getKey() + "=" + String.join(",", p.getValue()) + " "); + } + response.addHeader("X-Param-Map", map); + } +} diff --git a/test/java/header/app.java b/test/java/header/app.java new file mode 100644 index 00000000..02d56f4d --- /dev/null +++ b/test/java/header/app.java @@ -0,0 +1,34 @@ + +import java.io.IOException; +import java.io.PrintWriter; + +import javax.servlet.ServletConfig; +import javax.servlet.ServletException; +import javax.servlet.annotation.WebServlet; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +@WebServlet("/") +public class app extends HttpServlet +{ + @Override + public void doGet(HttpServletRequest request, HttpServletResponse response) + throws IOException, ServletException + { + response.setHeader("X-Set-Utf8-Value", "тест"); + response.setHeader("X-Set-Utf8-Name-Имя", "x"); + + response.addHeader("X-Add-Utf8-Value", "тест"); + response.addHeader("X-Add-Utf8-Name-Имя", "y"); + + response.addHeader("X-Add-Test", "v1"); + response.addHeader("X-Add-Test", null); + + response.setHeader("X-Set-Test1", "v1"); + response.setHeader("X-Set-Test1", null); + + response.setHeader("X-Set-Test2", "v1"); + response.setHeader("X-Set-Test2", ""); + } +} diff --git a/test/java/header_date/app.java b/test/java/header_date/app.java new file mode 100644 index 00000000..cedd569c --- /dev/null +++ b/test/java/header_date/app.java @@ -0,0 +1,22 @@ + +import java.io.IOException; +import java.io.PrintWriter; + +import javax.servlet.ServletConfig; +import javax.servlet.ServletException; +import javax.servlet.annotation.WebServlet; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +@WebServlet("/") +public class app extends HttpServlet +{ + @Override + public void doGet(HttpServletRequest request, HttpServletResponse response) + throws IOException, ServletException + { + response.setDateHeader("X-Set-Date", 1000); + response.addDateHeader("X-Get-Date", request.getDateHeader("X-Header")); + } +} diff --git a/test/java/header_int/app.java b/test/java/header_int/app.java new file mode 100644 index 00000000..3ac5478e --- /dev/null +++ b/test/java/header_int/app.java @@ -0,0 +1,22 @@ + +import java.io.IOException; +import java.io.PrintWriter; + +import javax.servlet.ServletConfig; +import javax.servlet.ServletException; +import javax.servlet.annotation.WebServlet; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +@WebServlet("/") +public class app extends HttpServlet +{ + @Override + public void doGet(HttpServletRequest request, HttpServletResponse response) + throws IOException, ServletException + { + response.setIntHeader("X-Set-Int", 1); + response.addHeader("X-Get-Int", Integer.toString(request.getIntHeader("X-Header"))); + } +} diff --git a/test/java/include/app.java b/test/java/include/app.java new file mode 100644 index 00000000..d7e36fc6 --- /dev/null +++ b/test/java/include/app.java @@ -0,0 +1,136 @@ + +import java.io.IOException; +import java.io.PrintWriter; + +import java.util.Map; + +import javax.servlet.DispatcherType; +import javax.servlet.RequestDispatcher; +import javax.servlet.ServletConfig; +import javax.servlet.ServletException; +import javax.servlet.ServletOutputStream; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletRequestWrapper; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpServletResponseWrapper; + +public class app extends HttpServlet +{ + private String id; + + private class RequestWrapper extends HttpServletRequestWrapper + { + public RequestWrapper(HttpServletRequest r) + { + super(r); + } + } + + private class ResponseWrapper extends HttpServletResponseWrapper + { + public ResponseWrapper(HttpServletResponse r) + { + super(r); + } + } + + @Override + public void init(ServletConfig sc) + throws ServletException + { + id = sc.getInitParameter("id"); + } + + private RequestDispatcher getRequestDispatcher(HttpServletRequest request, String str) + { + String disp = request.getParameter("disp"); + + if (disp != null && disp.equals("ctx")) { + return request.getServletContext().getRequestDispatcher(str); + } + + if (disp != null && disp.equals("name")) { + return request.getServletContext().getNamedDispatcher(str); + } + + if (disp == null || disp.equals("req")) { + return request.getRequestDispatcher(str); + } + + return null; + } + + @Override + public void doGet(HttpServletRequest request, HttpServletResponse response) + throws IOException, ServletException + { + String dtype = "" + request.getDispatcherType(); + + response.addHeader("X-" + dtype + "-Id", id); + response.addHeader("X-" + dtype + "-Request-URI", "" + request.getRequestURI()); + response.addHeader("X-" + dtype + "-Servlet-Path", "" + request.getServletPath()); + response.addHeader("X-" + dtype + "-Path-Info", "" + request.getPathInfo()); + response.addHeader("X-" + dtype + "-Query-String", "" + request.getQueryString()); + response.addHeader("X-" + dtype + "-Dispatcher-Type", "" + request.getDispatcherType()); + + response.setContentType("text/plain; charset=utf-8"); + + PrintWriter out = response.getWriter(); + + if (id.equals("inc")) { + String uri = request.getParameter("uri"); + + if (uri != null && request.getDispatcherType() != DispatcherType.INCLUDE) { + response.addHeader("X-Include", "" + uri); + + out.println("Before include."); + + RequestDispatcher d = getRequestDispatcher(request, uri); + + if (d == null) { + out.println("Dispatcher is null"); + return; + } + + try { + d.include(new RequestWrapper(request), new ResponseWrapper(response)); + } catch(Exception e) { + response.addHeader("X-Exception", "" + e); + out.println("Exception: " + e); + } + + response.addHeader("X-After-Include", "you-should-see-this"); + + out.println("After include."); + + return; + } + } + + if (id.equals("data")) { + out.println("app.doGet(): #" + this + ", " + id); + out.println("RequestURI: " + request.getRequestURI()); + out.println("ServletPath: " + request.getServletPath()); + out.println("PathInfo: " + request.getPathInfo()); + out.println("DispType: " + request.getDispatcherType()); + out.println("QueryString: " + request.getQueryString()); + + Map pmap = request.getParameterMap(); + + for (Map.Entry p : pmap.entrySet()) { + out.println("- " + p.getKey() + "=" + String.join(",", p.getValue())); + } + + out.println(RequestDispatcher.INCLUDE_REQUEST_URI + ": " + request.getAttribute(RequestDispatcher.INCLUDE_REQUEST_URI)); + out.println(RequestDispatcher.INCLUDE_CONTEXT_PATH + ": " + request.getAttribute(RequestDispatcher.INCLUDE_CONTEXT_PATH)); + out.println(RequestDispatcher.INCLUDE_SERVLET_PATH + ": " + request.getAttribute(RequestDispatcher.INCLUDE_SERVLET_PATH)); + out.println(RequestDispatcher.INCLUDE_PATH_INFO + ": " + request.getAttribute(RequestDispatcher.INCLUDE_PATH_INFO)); + out.println(RequestDispatcher.INCLUDE_QUERY_STRING + ": " + request.getAttribute(RequestDispatcher.INCLUDE_QUERY_STRING)); + + return; + } + + response.sendError(404); + } +} diff --git a/test/java/include/index.html b/test/java/include/index.html new file mode 100644 index 00000000..4f5a6379 --- /dev/null +++ b/test/java/include/index.html @@ -0,0 +1 @@ +This is index.html. diff --git a/test/java/include/web.xml b/test/java/include/web.xml new file mode 100644 index 00000000..2ed86f1d --- /dev/null +++ b/test/java/include/web.xml @@ -0,0 +1,37 @@ + + + + + + inc + app + idinc + + + + data + app + iddata + + + + inc + /inc/* + + + + data + /data/* + + + + data + /WEB-INF/index.html + /index.html + + + + diff --git a/test/java/jsp/index.jsp b/test/java/jsp/index.jsp new file mode 100644 index 00000000..0af00a46 --- /dev/null +++ b/test/java/jsp/index.jsp @@ -0,0 +1,2 @@ +<%@ page contentType="text/plain"%>This is plain text response for "<%= request.getMethod() %> <%= request.getRequestURI() %>". +<% response.addHeader("X-Unit-JSP", "ok"); %> diff --git a/test/java/mirror/app.java b/test/java/mirror/app.java new file mode 100644 index 00000000..45bc1d0d --- /dev/null +++ b/test/java/mirror/app.java @@ -0,0 +1,37 @@ + +import java.io.*; + +import javax.servlet.ServletConfig; +import javax.servlet.ServletException; +import javax.servlet.annotation.WebServlet; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +@WebServlet("/") +public class app extends HttpServlet +{ + @Override + public void doPost(HttpServletRequest request, HttpServletResponse response) + throws IOException, ServletException + { + StringBuilder buffer = new StringBuilder(); + BufferedReader reader = request.getReader(); + String line; + + while ((line = reader.readLine()) != null) { + buffer.append(line); + } + + String data = buffer.toString(); + + String dataLength = Integer.toString(data.length()); + response.setHeader("Content-Length", dataLength); + + response.setContentType("text/html"); + + PrintWriter out = response.getWriter(); + out.print(data); + out.flush(); + } +} diff --git a/test/java/path_translation/app.java b/test/java/path_translation/app.java new file mode 100644 index 00000000..ce0b9368 --- /dev/null +++ b/test/java/path_translation/app.java @@ -0,0 +1,56 @@ + +import java.io.IOException; +import java.io.PrintWriter; +import java.io.InputStream; + +import java.util.Set; + +import javax.servlet.ServletConfig; +import javax.servlet.ServletContext; +import javax.servlet.ServletException; +import javax.servlet.annotation.WebServlet; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +@WebServlet( urlPatterns = { "/", "/pt/*" } ) +public class app extends HttpServlet +{ + @Override + public void doGet(HttpServletRequest request, HttpServletResponse response) + throws IOException, ServletException + { + response.addHeader("X-Request-URI", "" + request.getRequestURI()); + response.addHeader("X-Servlet-Path", "" + request.getServletPath()); + response.addHeader("X-Path-Info", "" + request.getPathInfo()); + response.addHeader("X-Query-String", "" + request.getQueryString()); + response.addHeader("X-Path-Translated", "" + request.getPathTranslated()); + + response.setContentType("text/plain; charset=utf-8"); + + PrintWriter out = response.getWriter(); + ServletContext ctx = request.getServletContext(); + + String path = request.getParameter("path"); + + if (path != null) { + response.addHeader("X-Real-Path", "" + ctx.getRealPath(path)); + response.addHeader("X-Resource", "" + ctx.getResource(path)); + + Set paths = ctx.getResourcePaths(path); + + response.addHeader("X-Resource-Paths", "" + paths); + + InputStream is = ctx.getResourceAsStream(path); + + response.addHeader("X-Resource-As-Stream", "" + is); + + if (is != null) { + final byte[] buf = new byte[1024]; + int r = is.read(buf); + + out.println(new String(buf, 0, r, "utf-8")); + } + } + } +} diff --git a/test/java/path_translation/index.html b/test/java/path_translation/index.html new file mode 100644 index 00000000..4f5a6379 --- /dev/null +++ b/test/java/path_translation/index.html @@ -0,0 +1 @@ +This is index.html. diff --git a/test/java/post_params/app.java b/test/java/post_params/app.java new file mode 100644 index 00000000..0ed73d42 --- /dev/null +++ b/test/java/post_params/app.java @@ -0,0 +1,22 @@ + +import java.io.IOException; + +import javax.servlet.ServletException; +import javax.servlet.annotation.WebServlet; +import javax.servlet.http.Cookie; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +@WebServlet(urlPatterns = "/") +public class app extends HttpServlet +{ + @Override + public void doPost(HttpServletRequest request, HttpServletResponse response) + throws IOException, ServletException + { + response.addHeader("X-Var-1", request.getParameter("var1")); + response.addHeader("X-Var-2", "" + (request.getParameter("var2") != null)); + response.addHeader("X-Var-3", "" + (request.getParameter("var3") != null)); + } +} diff --git a/test/java/query_string/app.java b/test/java/query_string/app.java new file mode 100644 index 00000000..7962336b --- /dev/null +++ b/test/java/query_string/app.java @@ -0,0 +1,20 @@ + +import java.io.IOException; + +import javax.servlet.ServletConfig; +import javax.servlet.ServletException; +import javax.servlet.annotation.WebServlet; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +@WebServlet( urlPatterns = { "/" } ) +public class app extends HttpServlet +{ + @Override + public void doGet(HttpServletRequest request, HttpServletResponse response) + throws IOException, ServletException + { + response.addHeader("X-Query-String", "" + request.getQueryString()); + } +} diff --git a/test/java/request_listeners/app.java b/test/java/request_listeners/app.java new file mode 100644 index 00000000..6cbf7860 --- /dev/null +++ b/test/java/request_listeners/app.java @@ -0,0 +1,79 @@ + +import java.io.IOException; + +import javax.servlet.ServletException; +import javax.servlet.ServletRequestEvent; +import javax.servlet.ServletRequestListener; +import javax.servlet.ServletRequestAttributeEvent; +import javax.servlet.ServletRequestAttributeListener; +import javax.servlet.annotation.WebServlet; +import javax.servlet.annotation.WebListener; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +@WebListener +@WebServlet(urlPatterns = "/") +public class app extends HttpServlet implements + ServletRequestListener, + ServletRequestAttributeListener +{ + private static String request_initialized = ""; + private static String request_destroyed = ""; + private static String attribute_added = ""; + private static String attribute_removed = ""; + private static String attribute_replaced = ""; + + @Override + public void requestInitialized(ServletRequestEvent sre) + { + HttpServletRequest r = (HttpServletRequest) sre.getServletRequest(); + + request_initialized = r.getRequestURI(); + } + + @Override + public void requestDestroyed(ServletRequestEvent sre) + { + HttpServletRequest r = (HttpServletRequest) sre.getServletRequest(); + + request_destroyed = r.getRequestURI(); + + attribute_added = ""; + attribute_removed = ""; + attribute_replaced = ""; + } + + @Override + public void attributeAdded(ServletRequestAttributeEvent event) + { + attribute_added += event.getName() + "=" + event.getValue() + ";"; + } + + @Override + public void attributeRemoved(ServletRequestAttributeEvent event) + { + attribute_removed += event.getName() + "=" + event.getValue() + ";"; + } + + @Override + public void attributeReplaced(ServletRequestAttributeEvent event) + { + attribute_replaced += event.getName() + "=" + event.getValue() + ";"; + } + + @Override + public void doGet(HttpServletRequest request, HttpServletResponse response) + throws IOException, ServletException + { + request.setAttribute("var", request.getParameter("var1")); + request.setAttribute("var", request.getParameter("var2")); + request.setAttribute("var", request.getParameter("var3")); + + response.addHeader("X-Request-Initialized", request_initialized); + response.addHeader("X-Request-Destroyed", request_destroyed); + response.addHeader("X-Attr-Added", attribute_added); + response.addHeader("X-Attr-Removed", attribute_removed); + response.addHeader("X-Attr-Replaced", attribute_replaced); + } +} diff --git a/test/java/session/app.java b/test/java/session/app.java new file mode 100644 index 00000000..84d3fa55 --- /dev/null +++ b/test/java/session/app.java @@ -0,0 +1,30 @@ +import java.io.IOException; + +import javax.servlet.ServletException; +import javax.servlet.annotation.WebServlet; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; + +@WebServlet(urlPatterns = "/") +public class app extends HttpServlet +{ + @Override + public void doGet(HttpServletRequest request, HttpServletResponse response) + throws IOException, ServletException + { + HttpSession s = request.getSession(); + String old_var1 = (String) s.getAttribute("var1"); + s.setAttribute("var1", request.getParameter("var1")); + + if (old_var1 == null) { + response.addHeader("X-Var-1", "null"); + } else { + response.addHeader("X-Var-1", old_var1); + } + + response.addHeader("X-Session-Id", s.getId()); + response.addHeader("X-Session-New", "" + s.isNew()); + } +} diff --git a/test/java/session_inactive/app.java b/test/java/session_inactive/app.java new file mode 100644 index 00000000..f338fc89 --- /dev/null +++ b/test/java/session_inactive/app.java @@ -0,0 +1,27 @@ +import java.io.IOException; + +import javax.servlet.ServletException; +import javax.servlet.annotation.WebServlet; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; + +@WebServlet(urlPatterns = "/") +public class app extends HttpServlet +{ + @Override + public void doGet(HttpServletRequest request, HttpServletResponse response) + throws IOException, ServletException + { + HttpSession s = request.getSession(); + + if (s.isNew()) { + s.setMaxInactiveInterval(2); + } + + response.addHeader("X-Session-Id", s.getId()); + response.addDateHeader("X-Session-Last-Access-Time", s.getLastAccessedTime()); + response.addIntHeader("X-Session-Interval", s.getMaxInactiveInterval()); + } +} diff --git a/test/java/session_invalidate/app.java b/test/java/session_invalidate/app.java new file mode 100644 index 00000000..3f66290f --- /dev/null +++ b/test/java/session_invalidate/app.java @@ -0,0 +1,23 @@ +import java.io.IOException; + +import javax.servlet.ServletException; +import javax.servlet.annotation.WebServlet; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; + +@WebServlet(urlPatterns = "/") +public class app extends HttpServlet +{ + @Override + public void doGet(HttpServletRequest request, HttpServletResponse response) + throws IOException, ServletException + { + HttpSession s = request.getSession(); + + s.invalidate(); + + response.addHeader("X-Session-Id", s.getId()); + } +} diff --git a/test/java/session_listeners/app.java b/test/java/session_listeners/app.java new file mode 100644 index 00000000..603cc932 --- /dev/null +++ b/test/java/session_listeners/app.java @@ -0,0 +1,80 @@ + +import java.io.IOException; + +import javax.servlet.ServletException; +import javax.servlet.annotation.WebServlet; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import javax.servlet.http.HttpSession; +import javax.servlet.http.HttpSessionAttributeListener; +import javax.servlet.http.HttpSessionBindingEvent; +import javax.servlet.http.HttpSessionEvent; +import javax.servlet.http.HttpSessionIdListener; +import javax.servlet.http.HttpSessionListener; + +@WebServlet(urlPatterns = "/") +public class app extends HttpServlet implements + HttpSessionListener, + HttpSessionIdListener, + HttpSessionAttributeListener +{ + private static String session_created = ""; + private static String session_destroyed = ""; + private static String session_id_changed = ""; + private static String attribute_added = ""; + private static String attribute_removed = ""; + private static String attribute_replaced = ""; + + @Override + public void sessionCreated(HttpSessionEvent se) + { + session_created += se.getSession().getId(); + } + + @Override + public void sessionDestroyed(HttpSessionEvent se) + { + session_destroyed += se.getSession().getId(); + } + + @Override + public void sessionIdChanged(HttpSessionEvent event, String oldId) + { + session_id_changed += " " + oldId + "->" + event.getSession().getId(); + } + + @Override + public void attributeAdded(HttpSessionBindingEvent event) + { + attribute_added += event.getName() + "=" + event.getValue(); + } + + @Override + public void attributeRemoved(HttpSessionBindingEvent event) + { + attribute_removed += event.getName() + "=" + event.getValue(); + } + + @Override + public void attributeReplaced(HttpSessionBindingEvent event) + { + attribute_replaced += event.getName() + "=" + event.getValue(); + } + + @Override + public void doGet(HttpServletRequest request, HttpServletResponse response) + throws IOException, ServletException + { + HttpSession s = request.getSession(); + s.setAttribute("var1", request.getParameter("var1")); + + response.addHeader("X-Session-Id", s.getId()); + response.addHeader("X-Session-Created", session_created); + response.addHeader("X-Session-Destroyed", session_destroyed); + response.addHeader("X-Attr-Added", attribute_added); + response.addHeader("X-Attr-Removed", attribute_removed); + response.addHeader("X-Attr-Replaced", attribute_replaced); + } +} diff --git a/test/java/session_listeners/web.xml b/test/java/session_listeners/web.xml new file mode 100644 index 00000000..aedfe175 --- /dev/null +++ b/test/java/session_listeners/web.xml @@ -0,0 +1,14 @@ + + + + + app + + + app + + + diff --git a/test/java/url_pattern/app.java b/test/java/url_pattern/app.java new file mode 100644 index 00000000..88b071a2 --- /dev/null +++ b/test/java/url_pattern/app.java @@ -0,0 +1,39 @@ + +import java.io.IOException; +import java.io.PrintWriter; + +import javax.servlet.ServletConfig; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +public class app extends HttpServlet +{ + private String id; + + @Override + public void init(ServletConfig sc) + throws ServletException + { + id = sc.getInitParameter("id"); + } + + @Override + public void doGet(HttpServletRequest request, HttpServletResponse response) + throws IOException, ServletException + { + response.addHeader("X-Id", id); + response.addHeader("X-Request-URI", "" + request.getRequestURI()); + response.addHeader("X-Servlet-Path", "" + request.getServletPath()); + response.setHeader("X-Path-Info", "" + request.getPathInfo()); + + response.setContentType("text/plain; charset=utf-8"); + + PrintWriter out = response.getWriter(); + out.println("app.doGet(): #" + this + ", " + id); + out.println("RequestURI: " + request.getRequestURI()); + out.println("ServletPath: " + request.getServletPath()); + out.println("PathInfo: " + request.getPathInfo()); + } +} diff --git a/test/java/url_pattern/web.xml b/test/java/url_pattern/web.xml new file mode 100644 index 00000000..048400a6 --- /dev/null +++ b/test/java/url_pattern/web.xml @@ -0,0 +1,75 @@ + + + + + + servlet0 + app + idservlet0 + + + + servlet1 + app + idservlet1 + + + + servlet2 + app + idservlet2 + + + + servlet3 + app + idservlet3 + + + + servlet4 + app + idservlet4 + + + + default + app + iddefault + + + + servlet0 + /foo/* + + + + servlet1 + /foo/bar/* + + + + servlet2 + /baz/* + + + + servlet3 + /catalog + + + + servlet4 + *.bop + + + + default + / + + + + diff --git a/test/java/welcome_files/app.java b/test/java/welcome_files/app.java new file mode 100644 index 00000000..ce922531 --- /dev/null +++ b/test/java/welcome_files/app.java @@ -0,0 +1,67 @@ + +import java.io.IOException; +import java.io.PrintWriter; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import javax.servlet.annotation.WebFilter; +import javax.servlet.Filter; +import javax.servlet.FilterChain; +import javax.servlet.FilterConfig; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; + +public class app extends HttpServlet +{ + @WebFilter(urlPatterns = "*.jsp") + public static class jsp_filter implements Filter + { + @Override + public void init(FilterConfig filterConfig) { } + + @Override + public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) + throws IOException, ServletException + { + ((HttpServletResponse) response).addHeader("X-JSP-Filter", "1"); + + chain.doFilter(request, response); + } + + @Override + public void destroy() { } + } + + @WebFilter(urlPatterns = "*.txt") + public static class txt_filter implements Filter + { + @Override + public void init(FilterConfig filterConfig) { } + + @Override + public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) + throws IOException, ServletException + { + ((HttpServletResponse) response).addHeader("X-TXT-Filter", "1"); + + chain.doFilter(request, response); + } + + @Override + public void destroy() { } + } + + @Override + public void doGet(HttpServletRequest request, HttpServletResponse response) + throws IOException, ServletException + { + response.addHeader("X-App-Servlet", "1"); + response.setContentType("text/plain; charset=utf-8"); + + PrintWriter out = response.getWriter(); + out.println("App Servlet"); + } +} diff --git a/test/java/welcome_files/dir1/index.txt b/test/java/welcome_files/dir1/index.txt new file mode 100644 index 00000000..e7784d20 --- /dev/null +++ b/test/java/welcome_files/dir1/index.txt @@ -0,0 +1 @@ +This is index.txt. diff --git a/test/java/welcome_files/dir2/default.jsp b/test/java/welcome_files/dir2/default.jsp new file mode 100644 index 00000000..48627641 --- /dev/null +++ b/test/java/welcome_files/dir2/default.jsp @@ -0,0 +1,3 @@ +<%@ page contentType="text/html"%> +

You should see this on /dir2/ URL.

+<% response.addHeader("X-Unit-JSP", "ok"); %> diff --git a/test/java/welcome_files/dir2/index.html b/test/java/welcome_files/dir2/index.html new file mode 100644 index 00000000..5b111825 --- /dev/null +++ b/test/java/welcome_files/dir2/index.html @@ -0,0 +1 @@ +

You should see this on /dir2/ URL.

diff --git a/test/java/welcome_files/dir3/index.txt b/test/java/welcome_files/dir3/index.txt new file mode 100644 index 00000000..8a2b7dea --- /dev/null +++ b/test/java/welcome_files/dir3/index.txt @@ -0,0 +1 @@ +You should never see this. diff --git a/test/java/welcome_files/dir4/index.html b/test/java/welcome_files/dir4/index.html new file mode 100644 index 00000000..2cef75e2 --- /dev/null +++ b/test/java/welcome_files/dir4/index.html @@ -0,0 +1 @@ +

You should see this for /dir4/index.html or /dir4/ url. diff --git a/test/java/welcome_files/index.htm b/test/java/welcome_files/index.htm new file mode 100644 index 00000000..97e34cf5 --- /dev/null +++ b/test/java/welcome_files/index.htm @@ -0,0 +1 @@ +

You should see this ONLY for /index.htm url. diff --git a/test/java/welcome_files/web.xml b/test/java/welcome_files/web.xml new file mode 100644 index 00000000..6bbc7c8e --- /dev/null +++ b/test/java/welcome_files/web.xml @@ -0,0 +1,27 @@ + + + + + + index.txt + default.jsp + index.html + + + + app + app + + + + app + /dir3/index.txt + /dir4/index.txt + /dir5/index.html + + + + diff --git a/test/test_java_application.py b/test/test_java_application.py new file mode 100644 index 00000000..d603ed0f --- /dev/null +++ b/test/test_java_application.py @@ -0,0 +1,753 @@ +import time +import unittest +import unit + +class TestUnitJavaApplication(unit.TestUnitApplicationJava): + + def setUpClass(): + unit.TestUnit().check_modules('java') + + def test_java_application_cookies(self): + self.load('cookies') + + headers = self.get(headers={ + 'Cookie': 'var1=val1; var2=val2', + 'Host': 'localhost', + 'Connection': 'close' + })['headers'] + + self.assertEqual(headers['X-Cookie-1'], 'val1', 'cookie 1') + self.assertEqual(headers['X-Cookie-2'], 'val2', 'cookie 2') + + def test_java_application_filter(self): + self.load('filter') + + headers = self.get()['headers'] + + self.assertEqual(headers['X-Filter-Before'], '1', 'filter before') + self.assertEqual(headers['X-Filter-After'], '1', 'filter after') + + self.assertEqual(self.get(url='/test')['headers']['X-Filter-After'], + '0', 'filter after 2') + + def test_java_application_get_variables(self): + self.load('get_params') + + headers = self.get(url='/?var1=val1&var2=&var4=val4&var4=foo')['headers'] + + self.assertEqual(headers['X-Var-1'], 'val1', 'GET variables') + self.assertEqual(headers['X-Var-2'], 'true', 'GET variables 2') + self.assertEqual(headers['X-Var-3'], 'false', 'GET variables 3') + + self.assertEqual(headers['X-Param-Names'], 'var4 var2 var1 ', + 'getParameterNames') + self.assertEqual(headers['X-Param-Values'], 'val4 foo ', + 'getParameterValues') + self.assertEqual(headers['X-Param-Map'], + 'var2= var1=val1 var4=val4,foo ', 'getParameterMap') + + def test_java_application_post_variables(self): + self.load('post_params') + + headers = self.post(headers={ + 'Content-Type': 'application/x-www-form-urlencoded', + 'Host': 'localhost', + 'Connection': 'close' + }, body='var1=val1&var2=')['headers'] + + self.assertEqual(headers['X-Var-1'], 'val1', 'POST variables') + self.assertEqual(headers['X-Var-2'], 'true', 'POST variables 2') + self.assertEqual(headers['X-Var-3'], 'false', 'POST variables 3') + + def test_java_application_session(self): + self.load('session') + + headers = self.get(url='/?var1=val1')['headers'] + session_id = headers['X-Session-Id'] + + self.assertEqual(headers['X-Var-1'], 'null', 'variable empty') + self.assertEqual(headers['X-Session-New'], 'true', 'session create') + + headers = self.get(headers={ + 'Host': 'localhost', + 'Cookie': 'JSESSIONID=' + session_id, + 'Connection': 'close' + }, url='/?var1=val2')['headers'] + + self.assertEqual(headers['X-Var-1'], 'val1', 'variable') + self.assertEqual(headers['X-Session-New'], 'false', 'session resume') + self.assertEqual(session_id, headers['X-Session-Id'], 'session same id') + + def test_java_application_session_active(self): + self.load('session_inactive') + + resp = self.get() + session_id = resp['headers']['X-Session-Id'] + + self.assertEqual(resp['status'], 200, 'session init') + self.assertEqual(resp['headers']['X-Session-Interval'], '2', + 'session interval') + self.assertLess(abs(self.date_to_sec_epoch( + resp['headers']['X-Session-Last-Access-Time']) - self.sec_epoch()), + 5, 'session last access time') + + time.sleep(1) + + resp = self.get(headers={ + 'Host': 'localhost', + 'Cookie': 'JSESSIONID=' + session_id, + 'Connection': 'close' + }) + + self.assertEqual(resp['headers']['X-Session-Id'], session_id, + 'session active') + + session_id = resp['headers']['X-Session-Id'] + + time.sleep(1) + + resp = self.get(headers={ + 'Host': 'localhost', + 'Cookie': 'JSESSIONID=' + session_id, + 'Connection': 'close' + }) + + self.assertEqual(resp['headers']['X-Session-Id'], session_id, + 'session active 2') + + time.sleep(1) + + resp = self.get(headers={ + 'Host': 'localhost', + 'Cookie': 'JSESSIONID=' + session_id, + 'Connection': 'close' + }) + + self.assertEqual(resp['headers']['X-Session-Id'], session_id, + 'session active 3') + + def test_java_application_session_inactive(self): + self.load('session_inactive') + + resp = self.get() + session_id = resp['headers']['X-Session-Id'] + + time.sleep(3) + + resp = self.get(headers={ + 'Host': 'localhost', + 'Cookie': 'JSESSIONID=' + session_id, + 'Connection': 'close' + }) + + self.assertNotEqual(resp['headers']['X-Session-Id'], session_id, + 'session inactive') + + def test_java_application_session_invalidate(self): + self.load('session_invalidate') + + resp = self.get() + session_id = resp['headers']['X-Session-Id'] + + resp = self.get(headers={ + 'Host': 'localhost', + 'Cookie': 'JSESSIONID=' + session_id, + 'Connection': 'close' + }) + + self.assertNotEqual(resp['headers']['X-Session-Id'], session_id, + 'session invalidate') + + def test_java_application_session_listeners(self): + self.load('session_listeners') + + headers = self.get(url='/test?var1=val1')['headers'] + session_id = headers['X-Session-Id'] + + self.assertEqual(headers['X-Session-Created'], session_id, + 'session create') + self.assertEqual(headers['X-Attr-Added'], 'var1=val1', + 'attribute add') + + headers = self.get(headers={ + 'Host': 'localhost', + 'Cookie': 'JSESSIONID=' + session_id, + 'Connection': 'close' + }, url='/?var1=val2')['headers'] + + self.assertEqual(session_id, headers['X-Session-Id'], 'session same id') + self.assertEqual(headers['X-Attr-Replaced'], 'var1=val1', + 'attribute replace') + + headers = self.get(headers={ + 'Host': 'localhost', + 'Cookie': 'JSESSIONID=' + session_id, + 'Connection': 'close' + }, url='/')['headers'] + + self.assertEqual(session_id, headers['X-Session-Id'], 'session same id') + self.assertEqual(headers['X-Attr-Removed'], 'var1=val2', + 'attribute remove') + + def test_java_application_jsp(self): + self.load('jsp') + + headers = self.get(url='/index.jsp')['headers'] + + self.assertEqual(headers['X-Unit-JSP'], 'ok', 'JSP Ok header') + + def test_java_application_url_pattern(self): + self.load('url_pattern') + + headers = self.get(url='/foo/bar/index.html')['headers'] + + self.assertEqual(headers['X-Id'], 'servlet1', '#1 Servlet1 request') + self.assertEqual(headers['X-Request-URI'], '/foo/bar/index.html', '#1 request URI') + self.assertEqual(headers['X-Servlet-Path'], '/foo/bar', '#1 servlet path') + self.assertEqual(headers['X-Path-Info'], '/index.html', '#1 path info') + + headers = self.get(url='/foo/bar/index.bop')['headers'] + + self.assertEqual(headers['X-Id'], 'servlet1', '#2 Servlet1 request') + self.assertEqual(headers['X-Request-URI'], '/foo/bar/index.bop', '#2 request URI') + self.assertEqual(headers['X-Servlet-Path'], '/foo/bar', '#2 servlet path') + self.assertEqual(headers['X-Path-Info'], '/index.bop', '#2 path info') + + headers = self.get(url='/baz')['headers'] + + self.assertEqual(headers['X-Id'], 'servlet2', '#3 Servlet2 request') + self.assertEqual(headers['X-Request-URI'], '/baz', '#3 request URI') + self.assertEqual(headers['X-Servlet-Path'], '/baz', '#3 servlet path') + self.assertEqual(headers['X-Path-Info'], 'null', '#3 path info') + + headers = self.get(url='/baz/index.html')['headers'] + + self.assertEqual(headers['X-Id'], 'servlet2', '#4 Servlet2 request') + self.assertEqual(headers['X-Request-URI'], '/baz/index.html', '#4 request URI') + self.assertEqual(headers['X-Servlet-Path'], '/baz', '#4 servlet path') + self.assertEqual(headers['X-Path-Info'], '/index.html', '#4 path info') + + headers = self.get(url='/catalog')['headers'] + + self.assertEqual(headers['X-Id'], 'servlet3', '#5 Servlet3 request') + self.assertEqual(headers['X-Request-URI'], '/catalog', '#5 request URI') + self.assertEqual(headers['X-Servlet-Path'], '/catalog', '#5 servlet path') + self.assertEqual(headers['X-Path-Info'], 'null', '#5 path info') + + headers = self.get(url='/catalog/index.html')['headers'] + + self.assertEqual(headers['X-Id'], 'default', '#6 default request') + self.assertEqual(headers['X-Request-URI'], '/catalog/index.html', '#6 request URI') + self.assertEqual(headers['X-Servlet-Path'], '/catalog/index.html', '#6 servlet path') + self.assertEqual(headers['X-Path-Info'], 'null', '#6 path info') + + headers = self.get(url='/catalog/racecar.bop')['headers'] + + self.assertEqual(headers['X-Id'], 'servlet4', '#7 servlet4 request') + self.assertEqual(headers['X-Request-URI'], '/catalog/racecar.bop', '#7 request URI') + self.assertEqual(headers['X-Servlet-Path'], '/catalog/racecar.bop', '#7 servlet path') + self.assertEqual(headers['X-Path-Info'], 'null', '#7 path info') + + headers = self.get( url='/index.bop')['headers'] + + self.assertEqual(headers['X-Id'], 'servlet4', '#8 servlet4 request') + self.assertEqual(headers['X-Request-URI'], '/index.bop', '#8 request URI') + self.assertEqual(headers['X-Servlet-Path'], '/index.bop', '#8 servlet path') + self.assertEqual(headers['X-Path-Info'], 'null', '#8 path info') + + headers = self.get(url='/foo/baz')['headers'] + + self.assertEqual(headers['X-Id'], 'servlet0', '#9 servlet0 request') + self.assertEqual(headers['X-Request-URI'], '/foo/baz', '#9 request URI') + self.assertEqual(headers['X-Servlet-Path'], '/foo', '#9 servlet path') + self.assertEqual(headers['X-Path-Info'], '/baz', '#9 path info') + + headers = self.get()['headers'] + + self.assertEqual(headers['X-Id'], 'default', '#10 default request') + self.assertEqual(headers['X-Request-URI'], '/', '#10 request URI') + self.assertEqual(headers['X-Servlet-Path'], '/', '#10 servlet path') + self.assertEqual(headers['X-Path-Info'], 'null', '#10 path info') + + headers = self.get(url='/index.bop/')['headers'] + + self.assertEqual(headers['X-Id'], 'default', '#11 default request') + self.assertEqual(headers['X-Request-URI'], '/index.bop/', '#11 request URI') + self.assertEqual(headers['X-Servlet-Path'], '/index.bop/', '#11 servlet path') + self.assertEqual(headers['X-Path-Info'], 'null', '#11 path info') + + def test_java_application_header(self): + self.load('header') + + headers = self.get()['headers'] + + self.assertEqual(headers['X-Set-Utf8-Value'], '????', 'set Utf8 header value') + self.assertEqual(headers['X-Set-Utf8-Name-???'], 'x', 'set Utf8 header name') + self.assertEqual(headers['X-Add-Utf8-Value'], '????', 'add Utf8 header value') + self.assertEqual(headers['X-Add-Utf8-Name-???'], 'y', 'add Utf8 header name') + self.assertEqual(headers['X-Add-Test'], 'v1', 'add null header') + self.assertEqual('X-Set-Test1' in headers, False, 'set null header') + self.assertEqual(headers['X-Set-Test2'], '', 'set empty header') + + def test_java_application_content_type(self): + self.load('content_type') + + headers = self.get(url='/1')['headers'] + + self.assertEqual(headers['Content-Type'], 'text/plain;charset=utf-8', '#1 Content-Type header') + self.assertEqual(headers['X-Content-Type'], 'text/plain;charset=utf-8', '#1 response Content-Type') + self.assertEqual(headers['X-Character-Encoding'], 'utf-8', '#1 response charset') + + headers = self.get(url='/2')['headers'] + + self.assertEqual(headers['Content-Type'], 'text/plain;charset=iso-8859-1', '#2 Content-Type header') + self.assertEqual(headers['X-Content-Type'], 'text/plain;charset=iso-8859-1', '#2 response Content-Type') + self.assertEqual(headers['X-Character-Encoding'], 'iso-8859-1', '#2 response charset') + + headers = self.get(url='/3')['headers'] + + self.assertEqual(headers['Content-Type'], 'text/plain;charset=windows-1251', '#3 Content-Type header') + self.assertEqual(headers['X-Content-Type'], 'text/plain;charset=windows-1251', '#3 response Content-Type') + self.assertEqual(headers['X-Character-Encoding'], 'windows-1251', '#3 response charset') + + headers = self.get(url='/4')['headers'] + + self.assertEqual(headers['Content-Type'], 'text/plain;charset=windows-1251', '#4 Content-Type header') + self.assertEqual(headers['X-Content-Type'], 'text/plain;charset=windows-1251', '#4 response Content-Type') + self.assertEqual(headers['X-Character-Encoding'], 'windows-1251', '#4 response charset') + + headers = self.get(url='/5')['headers'] + + self.assertEqual(headers['Content-Type'], 'text/plain;charset=iso-8859-1', '#5 Content-Type header') + self.assertEqual(headers['X-Content-Type'], 'text/plain;charset=iso-8859-1', '#5 response Content-Type') + self.assertEqual(headers['X-Character-Encoding'], 'iso-8859-1', '#5 response charset') + + headers = self.get(url='/6')['headers'] + + self.assertEqual('Content-Type' in headers, False, '#6 no Content-Type header') + self.assertEqual('X-Content-Type' in headers, False, '#6 no response Content-Type') + self.assertEqual(headers['X-Character-Encoding'], 'utf-8', '#6 response charset') + + + headers = self.get(url='/7')['headers'] + + self.assertEqual(headers['Content-Type'], 'text/plain;charset=utf-8', '#7 Content-Type header') + self.assertEqual(headers['X-Content-Type'], 'text/plain;charset=utf-8', '#7 response Content-Type') + self.assertEqual(headers['X-Character-Encoding'], 'utf-8', '#7 response charset') + + headers = self.get(url='/8')['headers'] + + self.assertEqual(headers['Content-Type'], 'text/html;charset=utf-8', '#8 Content-Type header') + self.assertEqual(headers['X-Content-Type'], 'text/html;charset=utf-8', '#8 response Content-Type') + self.assertEqual(headers['X-Character-Encoding'], 'utf-8', '#8 response charset') + + def test_java_application_welcome_files(self): + self.load('welcome_files') + + headers = self.get()['headers'] + + resp = self.get(url='/dir1') + + self.assertEqual(resp['status'], 302, 'dir redirect expected') + + resp = self.get(url='/dir1/') + + self.assertEqual('This is index.txt.' in resp['body'], True, 'dir1 index body') + self.assertEqual(resp['headers']['X-TXT-Filter'], '1', 'TXT Filter header') + + headers = self.get(url='/dir2/')['headers'] + + self.assertEqual(headers['X-Unit-JSP'], 'ok', 'JSP Ok header') + self.assertEqual(headers['X-JSP-Filter'], '1', 'JSP Filter header') + + headers = self.get(url='/dir3/')['headers'] + + self.assertEqual(headers['X-App-Servlet'], '1', 'URL pattern overrides welcome file') + + headers = self.get(url='/dir4/')['headers'] + + self.assertEqual('X-App-Servlet' in headers, False, 'Static welcome file served first') + + headers = self.get(url='/dir5/')['headers'] + + self.assertEqual(headers['X-App-Servlet'], '1', 'Servlet for welcome file served when no static file found') + + def test_java_application_request_listeners(self): + self.load('request_listeners') + + headers = self.get(url='/test1')['headers'] + + self.assertEqual(headers['X-Request-Initialized'], '/test1', + 'request initialized event') + self.assertEqual(headers['X-Request-Destroyed'], '', + 'request destroyed event') + self.assertEqual(headers['X-Attr-Added'], '', + 'attribute added event') + self.assertEqual(headers['X-Attr-Removed'], '', + 'attribute removed event') + self.assertEqual(headers['X-Attr-Replaced'], '', + 'attribute replaced event') + + headers = self.get(url='/test2?var1=1')['headers'] + + self.assertEqual(headers['X-Request-Initialized'], '/test2', + 'request initialized event') + self.assertEqual(headers['X-Request-Destroyed'], '/test1', + 'request destroyed event') + self.assertEqual(headers['X-Attr-Added'], 'var=1;', + 'attribute added event') + self.assertEqual(headers['X-Attr-Removed'], 'var=1;', + 'attribute removed event') + self.assertEqual(headers['X-Attr-Replaced'], '', + 'attribute replaced event') + + headers = self.get(url='/test3?var1=1&var2=2')['headers'] + + self.assertEqual(headers['X-Request-Initialized'], '/test3', + 'request initialized event') + self.assertEqual(headers['X-Request-Destroyed'], '/test2', + 'request destroyed event') + self.assertEqual(headers['X-Attr-Added'], 'var=1;', + 'attribute added event') + self.assertEqual(headers['X-Attr-Removed'], 'var=2;', + 'attribute removed event') + self.assertEqual(headers['X-Attr-Replaced'], 'var=1;', + 'attribute replaced event') + + headers = self.get(url='/test4?var1=1&var2=2&var3=3')['headers'] + + self.assertEqual(headers['X-Request-Initialized'], '/test4', + 'request initialized event') + self.assertEqual(headers['X-Request-Destroyed'], '/test3', + 'request destroyed event') + self.assertEqual(headers['X-Attr-Added'], 'var=1;', + 'attribute added event') + self.assertEqual(headers['X-Attr-Removed'], '', + 'attribute removed event') + self.assertEqual(headers['X-Attr-Replaced'], 'var=1;var=2;', + 'attribute replaced event') + + def test_java_application_request_uri_forward(self): + self.load('forward') + + resp = self.get(url='/fwd?uri=%2Fdata%2Ftest%3Furi%3Dnew_uri%26a%3D2%26b%3D3&a=1&c=4') + headers = resp['headers'] + + self.assertEqual(headers['X-REQUEST-Id'], 'fwd', + 'initial request servlet mapping') + self.assertEqual(headers['X-Forward-To'], '/data/test?uri=new_uri&a=2&b=3', + 'forwarding triggered') + self.assertEqual(headers['X-REQUEST-Param-uri'], '/data/test?uri=new_uri&a=2&b=3', + 'original uri parameter') + self.assertEqual(headers['X-REQUEST-Param-a'], '1', + 'original a parameter') + self.assertEqual(headers['X-REQUEST-Param-c'], '4', + 'original c parameter') + + self.assertEqual(headers['X-FORWARD-Id'], 'data', + 'forward request servlet mapping') + self.assertEqual(headers['X-FORWARD-Request-URI'], '/data/test', + 'forward request uri') + self.assertEqual(headers['X-FORWARD-Servlet-Path'], '/data', + 'forward request servlet path') + self.assertEqual(headers['X-FORWARD-Path-Info'], '/test', + 'forward request path info') + self.assertEqual(headers['X-FORWARD-Query-String'], 'uri=new_uri&a=2&b=3', + 'forward request query string') + self.assertEqual(headers['X-FORWARD-Param-uri'], 'new_uri,/data/test?uri=new_uri&a=2&b=3', + 'forward uri parameter') + self.assertEqual(headers['X-FORWARD-Param-a'], '2,1', + 'forward a parameter') + self.assertEqual(headers['X-FORWARD-Param-b'], '3', + 'forward b parameter') + self.assertEqual(headers['X-FORWARD-Param-c'], '4', + 'forward c parameter') + + self.assertEqual(headers['X-javax.servlet.forward.request_uri'], '/fwd', + 'original request uri') + self.assertEqual(headers['X-javax.servlet.forward.context_path'], '', + 'original request context path') + self.assertEqual(headers['X-javax.servlet.forward.servlet_path'], '/fwd', + 'original request servlet path') + self.assertEqual(headers['X-javax.servlet.forward.path_info'], 'null', + 'original request path info') + self.assertEqual(headers['X-javax.servlet.forward.query_string'], 'uri=%2Fdata%2Ftest%3Furi%3Dnew_uri%26a%3D2%26b%3D3&a=1&c=4', + 'original request query') + + self.assertEqual('Before forwarding' in resp['body'], False, + 'discarded data added before forward() call') + self.assertEqual('X-After-Forwarding' in headers, False, + 'cannot add headers after forward() call') + self.assertEqual('After forwarding' in resp['body'], False, + 'cannot add data after forward() call') + + def test_java_application_named_dispatcher_forward(self): + self.load('forward') + + resp = self.get(url='/fwd?disp=name&uri=data') + headers = resp['headers'] + + self.assertEqual(headers['X-REQUEST-Id'], 'fwd', + 'initial request servlet mapping') + self.assertEqual(headers['X-Forward-To'], 'data', + 'forwarding triggered') + + self.assertEqual(headers['X-FORWARD-Id'], 'data', + 'forward request servlet mapping') + self.assertEqual(headers['X-FORWARD-Request-URI'], '/fwd', + 'forward request uri') + self.assertEqual(headers['X-FORWARD-Servlet-Path'], '/fwd', + 'forward request servlet path') + self.assertEqual(headers['X-FORWARD-Path-Info'], 'null', + 'forward request path info') + self.assertEqual(headers['X-FORWARD-Query-String'], 'disp=name&uri=data', + 'forward request query string') + + self.assertEqual(headers['X-javax.servlet.forward.request_uri'], 'null', + 'original request uri') + self.assertEqual(headers['X-javax.servlet.forward.context_path'], 'null', + 'original request context path') + self.assertEqual(headers['X-javax.servlet.forward.servlet_path'], 'null', + 'original request servlet path') + self.assertEqual(headers['X-javax.servlet.forward.path_info'], 'null', + 'original request path info') + self.assertEqual(headers['X-javax.servlet.forward.query_string'], 'null', + 'original request query') + + self.assertEqual('Before forwarding' in resp['body'], False, + 'discarded data added before forward() call') + self.assertEqual('X-After-Forwarding' in headers, False, + 'cannot add headers after forward() call') + self.assertEqual('After forwarding' in resp['body'], False, + 'cannot add data after forward() call') + + def test_java_application_request_uri_include(self): + self.load('include') + + resp = self.get(url='/inc?uri=/data/test') + headers = resp['headers'] + body = resp['body'] + + self.assertEqual(headers['X-REQUEST-Id'], 'inc', + 'initial request servlet mapping') + self.assertEqual(headers['X-Include'], '/data/test', + 'including triggered') + + self.assertEqual('X-INCLUDE-Id' in headers, False, + 'unable to add headers in include request') + + self.assertEqual('javax.servlet.include.request_uri: /data/test' in body, + True, 'include request uri') +# self.assertEqual('javax.servlet.include.context_path: ' in body, +# 'include request context path') + self.assertEqual('javax.servlet.include.servlet_path: /data' in body, + True, 'include request servlet path') + self.assertEqual('javax.servlet.include.path_info: /test' in body, + True, 'include request path info') + self.assertEqual('javax.servlet.include.query_string: null' in body, + True, 'include request query') + + self.assertEqual('Before include' in body, True, + 'preserve data added before include() call') + self.assertEqual(headers['X-After-Include'], 'you-should-see-this', + 'add headers after include() call') + self.assertEqual('After include' in body, True, + 'add data after include() call') + + def test_java_application_named_dispatcher_include(self): + self.load('include') + + resp = self.get(url='/inc?disp=name&uri=data') + headers = resp['headers'] + body = resp['body'] + + self.assertEqual(headers['X-REQUEST-Id'], 'inc', + 'initial request servlet mapping') + self.assertEqual(headers['X-Include'], 'data', + 'including triggered') + + self.assertEqual('X-INCLUDE-Id' in headers, False, + 'unable to add headers in include request') + + self.assertEqual('javax.servlet.include.request_uri: null' in body, + True, 'include request uri') +# self.assertEqual('javax.servlet.include.context_path: null' in body, +# 'include request context path') + self.assertEqual('javax.servlet.include.servlet_path: null' in body, + True, 'include request servlet path') + self.assertEqual('javax.servlet.include.path_info: null' in body, + True, 'include request path info') + self.assertEqual('javax.servlet.include.query_string: null' in body, + True, 'include request query') + + self.assertEqual('Before include' in body, True, + 'preserve data added before include() call') + self.assertEqual(headers['X-After-Include'], 'you-should-see-this', + 'add headers after include() call') + self.assertEqual('After include' in body, True, + 'add data after include() call') + + def test_java_application_path_translation(self): + self.load('path_translation') + + headers = self.get(url='/pt/test?path=/')['headers'] + + self.assertEqual(headers['X-Servlet-Path'], '/pt', + 'matched servlet path') + self.assertEqual(headers['X-Path-Info'], '/test', + 'the rest of the path') + self.assertEqual(headers['X-Path-Translated'], + headers['X-Real-Path'] + headers['X-Path-Info'], + 'translated path is the app root + path info') + self.assertEqual( + headers['X-Resource-Paths'].endswith('/WEB-INF/, /index.html]'), + True, 'app root directory content') + self.assertEqual(headers['X-Resource-As-Stream'], 'null', + 'no resource stream for root path') + + headers = self.get(url='/test?path=/none')['headers'] + + self.assertEqual(headers['X-Servlet-Path'], '/test', + 'matched whole path') + self.assertEqual(headers['X-Path-Info'], 'null', + 'the rest of the path is null, whole path matched') + self.assertEqual(headers['X-Path-Translated'], 'null', + 'translated path is null because path info is null') + self.assertEqual(headers['X-Real-Path'].endswith('/none'), True, + 'read path is not null') + self.assertEqual(headers['X-Resource-Paths'], 'null', + 'no resource found') + self.assertEqual(headers['X-Resource-As-Stream'], 'null', + 'no resource stream') + + def test_java_application_query_string(self): + self.load('query_string') + + self.assertEqual(self.get(url='/?a=b')['headers']['X-Query-String'], + 'a=b', 'query string') + + def test_java_application_query_empty(self): + self.load('query_string') + + self.assertEqual(self.get(url='/?')['headers']['X-Query-String'], '', + 'query string empty') + + def test_java_application_query_absent(self): + self.load('query_string') + + self.assertEqual(self.get()['headers']['X-Query-String'], 'null', + 'query string absent') + + def test_java_application_empty(self): + self.load('empty') + + self.assertEqual(self.get()['status'], 200, 'empty') + + def test_java_application_keepalive_body(self): + self.load('mirror') + + (resp, sock) = self.post(headers={ + 'Connection': 'keep-alive', + 'Content-Type': 'text/html', + 'Host': 'localhost' + }, start=True, body='0123456789' * 500) + + self.assertEqual(resp['body'], '0123456789' * 500, 'keep-alive 1') + + resp = self.post(headers={ + 'Connection': 'close', + 'Content-Type': 'text/html', + 'Host': 'localhost' + }, sock=sock, body='0123456789') + + self.assertEqual(resp['body'], '0123456789', 'keep-alive 2') + + def test_java_application_http_10(self): + self.load('empty') + + self.assertEqual(self.get(http_10=True)['status'], 200, 'HTTP 1.0') + + def test_java_application_no_method(self): + self.load('empty') + + self.assertEqual(self.post()['status'], 405, 'no method') + + def test_java_application_get_header(self): + self.load('get_header') + + self.assertEqual(self.get(headers={ + 'X-Header': 'blah', + 'Content-Type': 'text/html', + 'Host': 'localhost' + })['headers']['X-Reply'], 'blah', 'get header') + + def test_java_application_get_header_empty(self): + self.load('get_header') + + self.assertNotIn('X-Reply', self.get()['headers'], 'get header empty') + + def test_java_application_get_headers(self): + self.load('get_headers') + + headers = self.get(headers={ + 'X-Header': ['blah', 'blah'], + 'Content-Type': 'text/html', + 'Host': 'localhost' + })['headers'] + + self.assertEqual(headers['X-Reply-0'], 'blah', 'get headers') + self.assertEqual(headers['X-Reply-1'], 'blah', 'get headers 2') + + def test_java_application_get_headers_empty(self): + self.load('get_headers') + + self.assertNotIn('X-Reply-0', self.get()['headers'], + 'get headers empty') + + def test_java_application_get_header_names(self): + self.load('get_header_names') + + headers = self.get()['headers'] + + self.assertRegex(headers['X-Reply-0'], r'(?:Host|Connection)', + 'get header names') + self.assertRegex(headers['X-Reply-1'], r'(?:Host|Connection)', + 'get header names 2') + self.assertNotEqual(headers['X-Reply-0'], headers['X-Reply-1'], + 'get header names not equal') + + def test_java_application_get_header_names_empty(self): + self.load('get_header_names') + + self.assertNotIn('X-Reply-0', self.get(headers={})['headers'], + 'get header names empty') + + def test_java_application_header_int(self): + self.load('header_int') + + headers = self.get(headers={ + 'X-Header': '2', + 'Content-Type': 'text/html', + 'Host': 'localhost' + })['headers'] + + self.assertEqual(headers['X-Set-Int'], '1', 'set int header') + self.assertEqual(headers['X-Get-Int'], '2', 'get int header') + + def test_java_application_header_date(self): + self.load('header_date') + + date = 'Fri, 15 Mar 2019 14:45:34 GMT' + + headers = self.get(headers={ + 'X-Header': date, + 'Content-Type': 'text/html', + 'Host': 'localhost' + })['headers'] + + self.assertEqual(headers['X-Set-Date'], 'Thu, 01 Jan 1970 00:00:01 GMT', + 'set date header') + self.assertEqual(headers['X-Get-Date'], date, 'get date header') + +if __name__ == '__main__': + TestUnitJavaApplication.main() diff --git a/test/unit.py b/test/unit.py index 7a51eb20..a0de82e7 100644 --- a/test/unit.py +++ b/test/unit.py @@ -600,6 +600,72 @@ class TestUnitApplicationNode(TestUnitApplicationProto): } }) +class TestUnitApplicationJava(TestUnitApplicationProto): + def load(self, script, name='app'): + + app_path = self.testdir + '/java' + web_inf_path = app_path + '/WEB-INF/' + classes_path = web_inf_path + 'classes/' + + script_path = self.current_dir + '/java/' + script + '/' + + if not os.path.isdir(app_path): + os.makedirs(app_path) + + src = [] + + for f in os.listdir(script_path): + if f.endswith('.java'): + src.append(script_path + f) + continue + + if f.startswith('.') or f == 'Makefile': + continue + + if os.path.isdir(script_path + f): + if f == 'WEB-INF': + continue + + shutil.copytree(script_path + f, app_path + '/' + f) + continue + + if f == 'web.xml': + if not os.path.isdir(web_inf_path): + os.makedirs(web_inf_path) + + shutil.copy2(script_path + f, web_inf_path) + else: + shutil.copy2(script_path + f, app_path) + + if src: + if not os.path.isdir(classes_path): + os.makedirs(classes_path) + + javac = ['javac', '-encoding', 'utf-8', '-d', classes_path, + '-classpath', + self.pardir + '/build/tomcat-servlet-api-9.0.13.jar'] + javac.extend(src) + + process = subprocess.Popen(javac) + process.communicate() + + self.conf({ + "listeners": { + "*:7080": { + "application": script + } + }, + "applications": { + script: { + "unit_jars": self.pardir + '/build', + "type": "java", + "processes": { "spare": 0 }, + "working_directory": script_path, + "webapp": app_path + } + } + }) + class TestUnitApplicationPerl(TestUnitApplicationProto): def load(self, script, name='psgi.pl'): self.conf({ -- cgit From a5dd0f8aa9b81921ff28c486a39fd46607dbdbd9 Mon Sep 17 00:00:00 2001 From: Valentin Bartenev Date: Thu, 28 Feb 2019 20:20:41 +0300 Subject: Made QUERY_STRING mandatory. According to CGI/1.1 RFC 3875: The server MUST set this variable; if the Script-URI does not include a query component, the QUERY_STRING MUST be defined as an empty string (""). Python's PEP 333(3) allows omitting it in WSGI interface; PHP docs force no requirements; PSGI and Rack specifications require it even if empty. When nginx proxies requests over FastCGI, it always provides QUERY_STRING. and some PHP apps have been observed to fail if it is missing (see issue #201 on GitHub). A drawback of this change (besides a small overhead) is that there will be no easy way to tell a missing query string from an empty one (i.e. requests with or without the "?" character); yet, it's negligible compared to the possible benefits of wider application compatibility. This closes #226 issue on GitHub. --- test/test_python_application.py | 1 - 1 file changed, 1 deletion(-) (limited to 'test') diff --git a/test/test_python_application.py b/test/test_python_application.py index da5d3ba2..a8631085 100644 --- a/test/test_python_application.py +++ b/test/test_python_application.py @@ -65,7 +65,6 @@ class TestUnitPythonApplication(unit.TestUnitApplicationPython): self.assertEqual(resp['headers']['Query-String'], '', 'query string empty') - @unittest.expectedFailure def test_python_application_query_string_absent(self): self.load('query_string') -- cgit From 38ea191fbb91db000b1e68185359e612e7e47c54 Mon Sep 17 00:00:00 2001 From: Andrey Zelenkov Date: Thu, 28 Feb 2019 21:18:33 +0300 Subject: Tests: fixed PHP "disable_functions" and "disable_classes" tests. --- test/php/date_time/index.php | 3 +- test/php/highlight_file_exec/index.php | 4 -- test/php/time_exec/index.php | 4 ++ test/test_php_application.py | 118 +++++++++++++++------------------ 4 files changed, 60 insertions(+), 69 deletions(-) delete mode 100644 test/php/highlight_file_exec/index.php create mode 100644 test/php/time_exec/index.php (limited to 'test') diff --git a/test/php/date_time/index.php b/test/php/date_time/index.php index 4e06fdf9..42992c3f 100644 --- a/test/php/date_time/index.php +++ b/test/php/date_time/index.php @@ -1,4 +1,5 @@ format('u'); ?> diff --git a/test/php/highlight_file_exec/index.php b/test/php/highlight_file_exec/index.php deleted file mode 100644 index adcd5ed8..00000000 --- a/test/php/highlight_file_exec/index.php +++ /dev/null @@ -1,4 +0,0 @@ - diff --git a/test/php/time_exec/index.php b/test/php/time_exec/index.php new file mode 100644 index 00000000..05d59d28 --- /dev/null +++ b/test/php/time_exec/index.php @@ -0,0 +1,4 @@ + diff --git a/test/test_php_application.py b/test/test_php_application.py index f077cd3b..ac74359d 100644 --- a/test/test_php_application.py +++ b/test/test_php_application.py @@ -7,9 +7,11 @@ class TestUnitPHPApplication(unit.TestUnitApplicationPHP): def setUpClass(): unit.TestUnit().check_modules('php') - def search_disabled(self, name): - p = re.compile(name + '\(\) has been disabled') - return self.search_in_log(p) + def before_disable_functions(self): + body = self.get()['body'] + + self.assertRegex(body, r'time: \d+', 'disable_functions before time') + self.assertRegex(body, r'exec: \/\w+', 'disable_functions before exec') def test_php_application_variables(self): self.load('variables') @@ -239,109 +241,97 @@ class TestUnitPHPApplication(unit.TestUnitApplicationPHP): 'ini value repeat') def test_php_application_disable_functions_exec(self): - self.load('highlight_file_exec') - - self.conf({"admin": { "disable_functions": "exec" }}, - 'applications/highlight_file_exec/options') - - self.get() - - self.assertIsNotNone(self.search_disabled('exec'), - 'disable_functions exec') - self.assertIsNone(self.search_disabled('highlight_file'), - 'disable_functions highlight_file') + self.load('time_exec') - def test_php_application_disable_functions_highlight_file(self): - self.load('highlight_file_exec') + self.before_disable_functions() - self.conf({"admin": { "disable_functions": "highlight_file" }}, - 'applications/highlight_file_exec/options') + self.conf({"admin": { "disable_functions": "exec" }}, + 'applications/time_exec/options') - self.get() + body = self.get()['body'] - self.assertIsNone(self.search_disabled('exec'), - 'disable_functions exec') - self.assertIsNotNone(self.search_disabled('highlight_file'), - 'disable_functions highlight_file') + self.assertRegex(body, r'time: \d+', 'disable_functions time') + self.assertNotRegex(body, r'exec: \/\w+', 'disable_functions exec') def test_php_application_disable_functions_comma(self): - self.load('highlight_file_exec') + self.load('time_exec') + + self.before_disable_functions() - self.conf({"admin": { "disable_functions": "exec,highlight_file" }}, - 'applications/highlight_file_exec/options') + self.conf({"admin": { "disable_functions": "exec,time" }}, + 'applications/time_exec/options') - self.get() + body = self.get()['body'] - self.assertIsNotNone(self.search_disabled('exec'), - 'disable_functions exec') - self.assertIsNotNone(self.search_disabled('highlight_file'), - 'disable_functions highlight_file') + self.assertNotRegex(body, r'time: \d+', 'disable_functions comma time') + self.assertNotRegex(body, r'exec: \/\w+', + 'disable_functions comma exec') def test_php_application_disable_functions_space(self): - self.load('highlight_file_exec') + self.load('time_exec') - self.conf({"admin": { "disable_functions": "exec highlight_file" }}, - 'applications/highlight_file_exec/options') + self.before_disable_functions() - self.get() + self.conf({"admin": { "disable_functions": "exec time" }}, + 'applications/time_exec/options') - self.assertIsNotNone(self.search_disabled('exec'), - 'disable_functions exec') - self.assertIsNotNone(self.search_disabled('highlight_file'), - 'disable_functions highlight_file') + body = self.get()['body'] + + self.assertNotRegex(body, r'time: \d+', 'disable_functions space time') + self.assertNotRegex(body, r'exec: \/\w+', + 'disable_functions space exec') def test_php_application_disable_functions_user(self): - self.load('highlight_file_exec') + self.load('time_exec') + + self.before_disable_functions() self.conf({"user": { "disable_functions": "exec" }}, - 'applications/highlight_file_exec/options') + 'applications/time_exec/options') - self.get() + body = self.get()['body'] - self.assertIsNotNone(self.search_disabled('exec'), - 'disable_functions exec') - self.assertIsNone(self.search_disabled('highlight_file'), - 'disable_functions highlight_file') + self.assertRegex(body, r'time: \d+', 'disable_functions user time') + self.assertNotRegex(body, r'exec: \/\w+', 'disable_functions user exec') def test_php_application_disable_functions_nonexistent(self): - self.load('highlight_file_exec') + self.load('time_exec') + + self.before_disable_functions() self.conf({"admin": { "disable_functions": "blah" }}, - 'applications/highlight_file_exec/options') + 'applications/time_exec/options') - self.get() + body = self.get()['body'] - self.assertIsNone(self.search_disabled('exec'), - 'disable_functions exec') - self.assertIsNone(self.search_disabled('highlight_file'), - 'disable_functions highlight_file') + self.assertRegex(body, r'time: \d+', + 'disable_functions nonexistent time') + self.assertRegex(body, r'exec: \/\w+', + 'disable_functions nonexistent exec') def test_php_application_disable_classes(self): self.load('date_time') - self.get() - - self.assertIsNone(self.search_disabled('DateTime'), + self.assertRegex(self.get()['body'], r'012345', 'disable_classes before') self.conf({"admin": { "disable_classes": "DateTime" }}, 'applications/date_time/options') - self.get() - - self.assertIsNotNone(self.search_disabled('DateTime'), - 'disable_classes') + self.assertNotRegex(self.get()['body'], r'012345', + 'disable_classes before') def test_php_application_disable_classes_user(self): self.load('date_time') + self.assertRegex(self.get()['body'], r'012345', + 'disable_classes before') + self.conf({"user": { "disable_classes": "DateTime" }}, 'applications/date_time/options') - self.get() - - self.assertIsNotNone(self.search_disabled('DateTime'), - 'disable_classes user') + self.assertNotRegex(self.get()['body'], r'012345', + 'disable_classes before') if __name__ == '__main__': TestUnitPHPApplication.main() -- cgit From c1751f9de69638da89fda2ec17a693b7ec2de5c5 Mon Sep 17 00:00:00 2001 From: Andrey Zelenkov Date: Thu, 28 Feb 2019 21:19:32 +0300 Subject: Tests: specify ssl_version option. TLS is explicitly selected to prevent using of SSL protocol in ssl.get_server_certificate() call for Python 3.4 and older. --- test/unit.py | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) (limited to 'test') diff --git a/test/unit.py b/test/unit.py index a0de82e7..6cca7f48 100644 --- a/test/unit.py +++ b/test/unit.py @@ -718,7 +718,19 @@ class TestUnitApplicationTLS(TestUnitApplicationProto): **kwargs) def get_server_certificate(self, addr=('127.0.0.1', 7080)): - return ssl.get_server_certificate(addr) + + ssl_list = dir(ssl) + + if 'PROTOCOL_TLS' in ssl_list: + ssl_version = ssl.PROTOCOL_TLS + + elif 'PROTOCOL_TLSv1_2' in ssl_list: + ssl_version = ssl.PROTOCOL_TLSv1_2 + + else: + ssl_version = ssl.PROTOCOL_TLSv1_1 + + return ssl.get_server_certificate(addr, ssl_version=ssl_version) def load(self, script, name=None): if name is None: -- cgit From 3b2c1d0eaaf8252242d2a164ad768a985e8ded5c Mon Sep 17 00:00:00 2001 From: Alexander Borisov Date: Fri, 1 Mar 2019 16:50:25 +0300 Subject: Perl: added implementation delayed response and streaming body. --- test/test_perl_application.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'test') diff --git a/test/test_perl_application.py b/test/test_perl_application.py index 6fd0f78e..4609c2bd 100644 --- a/test/test_perl_application.py +++ b/test/test_perl_application.py @@ -45,7 +45,7 @@ class TestUnitPerlApplication(unit.TestUnitApplicationPerl): 'Psgi-Multiprocess': '1', 'Psgi-Run-Once': '', 'Psgi-Nonblocking': '', - 'Psgi-Streaming': '' + 'Psgi-Streaming': '1' }, 'headers') self.assertEqual(resp['body'], body, 'body') -- cgit From 754b85c3eedc6717b9bb94fe82a80f36f25a3e9f Mon Sep 17 00:00:00 2001 From: Andrey Zelenkov Date: Fri, 1 Mar 2019 17:13:51 +0300 Subject: Tests: Perl streaming body and delayed response simple tests. --- test/perl/delayed_response/psgi.pl | 10 ++++++++++ test/perl/streaming_body/psgi.pl | 13 +++++++++++++ test/test_perl_application.py | 16 ++++++++++++++++ 3 files changed, 39 insertions(+) create mode 100644 test/perl/delayed_response/psgi.pl create mode 100644 test/perl/streaming_body/psgi.pl (limited to 'test') diff --git a/test/perl/delayed_response/psgi.pl b/test/perl/delayed_response/psgi.pl new file mode 100644 index 00000000..f934c3a7 --- /dev/null +++ b/test/perl/delayed_response/psgi.pl @@ -0,0 +1,10 @@ +my $app = sub { + my ($environ) = @_; + + return sub { + (my $responder = shift)->([200, [ + 'Content-Type' => 'text/plain', + 'Content-Length' => '12' + ], ["Hello World!"]]); + } +}; diff --git a/test/perl/streaming_body/psgi.pl b/test/perl/streaming_body/psgi.pl new file mode 100644 index 00000000..a3e54ee0 --- /dev/null +++ b/test/perl/streaming_body/psgi.pl @@ -0,0 +1,13 @@ +my $app = sub { + my ($environ) = @_; + + return sub { + my $writer = (my $responder = shift)->([200, [ + 'Content-Type' => 'text/plain', + 'Content-Length' => '12' + ]]); + + $writer->write("Hello World!"); + $writer->close; + }; +}; diff --git a/test/test_perl_application.py b/test/test_perl_application.py index 4609c2bd..b169baab 100644 --- a/test/test_perl_application.py +++ b/test/test_perl_application.py @@ -200,5 +200,21 @@ class TestUnitPerlApplication(unit.TestUnitApplicationPerl): self.search_in_log(r'\[error\].+IOFake close\(\) called'), 'body io fake close') + def test_perl_delayed_response(self): + self.load('delayed_response') + + resp = self.get() + + self.assertEqual(resp['status'], 200, 'status') + self.assertEqual(resp['body'], 'Hello World!', 'body') + + def test_perl_streaming_body(self): + self.load('streaming_body') + + resp = self.get() + + self.assertEqual(resp['status'], 200, 'status') + self.assertEqual(resp['body'], 'Hello World!', 'body') + if __name__ == '__main__': TestUnitPerlApplication.main() -- cgit