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()