Repository: trafficserver
Updated Branches:
  refs/heads/master e895bcc6a -> 51ea4aa9d


http://git-wip-us.apache.org/repos/asf/trafficserver/blob/51ea4aa9/ci/tsqa/tests/test_keepalive.py
----------------------------------------------------------------------
diff --git a/ci/tsqa/tests/test_keepalive.py b/ci/tsqa/tests/test_keepalive.py
new file mode 100644
index 0000000..0e501ce
--- /dev/null
+++ b/ci/tsqa/tests/test_keepalive.py
@@ -0,0 +1,476 @@
+#  Licensed to the Apache Software Foundation (ASF) under one
+#  or more contributor license agreements.  See the NOTICE file
+#  distributed with this work for additional information
+#  regarding copyright ownership.  The ASF licenses this file
+#  to you under the Apache License, Version 2.0 (the
+#  "License"); you may not use this file except in compliance
+#  with the License.  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.
+
+import uuid
+import requests
+import time
+import logging
+import socket
+
+import helpers
+
+import tsqa.test_cases
+import tsqa.utils
+import tsqa.endpoint
+
+log = logging.getLogger(__name__)
+
+import SocketServer
+
+
+class KeepaliveTCPHandler(SocketServer.BaseRequestHandler):
+    """
+    A subclass of RequestHandler which will return a connection uuid
+    """
+
+    def handle(self):
+        # Receive the data in small chunks and retransmit it
+        start = time.time()
+        conn_id = uuid.uuid4().hex
+        while True:
+            now = time.time() - start
+            data = self.request.recv(4096).strip()
+            if data:
+                log.debug('Sending data back to the client: 
{uid}'.format(uid=conn_id))
+            else:
+                log.debug('Client disconnected: 
{timeout}seconds'.format(timeout=now))
+                break
+            body = conn_id
+            resp = ('HTTP/1.1 200 OK\r\n'
+                    'Content-Length: {content_length}\r\n'
+                    'Content-Type: text/html; charset=UTF-8\r\n'
+                    'Connection: keep-alive\r\n'
+                    '\r\n'
+                    '{body}'.format(content_length=len(body), body=body))
+            self.request.sendall(resp)
+
+
+class KeepAliveInMixin(object):
+    """Mixin for keep alive in.
+
+       TODO: Allow protocol to be specified for ssl traffic
+    """
+    def _get_socket(self):
+        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+        s.connect(('127.0.0.1', 
int(self.configs['records.config']['CONFIG']['proxy.config.http.server_ports'])))
+        return s
+
+    def _headers_to_str(self, headers):
+        if headers is None:
+            headers = {}
+        request = ''
+        for k, v in headers.iteritems():
+            request += '{0}: {1}\r\n'.format(k, v)
+        return request
+
+    def _aux_KA_working_path_connid(self, protocol, headers=None):
+        # connect tcp
+        s = self._get_socket()
+
+        request = ('GET / HTTP/1.1\r\n'
+                   'Host: foobar.com\r\n')
+        request += self._headers_to_str(headers)
+        request += '\r\n'
+
+        for x in xrange(1, 10):
+            s.send(request)
+            response = s.recv(4096)
+            # cheat, since we know what the body should have
+            if '\r\n\r\n' not in response:
+                response += s.recv(4096)
+            self.assertIn('HTTP/1.1 200 OK', response)
+            self.assertIn('hello', response)
+
+    def _aux_working_path(self, protocol, headers=None):
+        # connect tcp
+        s = self._get_socket()
+
+        request = ('GET /exists/ HTTP/1.1\r\n'
+                   'Host: foobar.com\r\n')
+        request += self._headers_to_str(headers)
+        request += '\r\n'
+
+        for x in xrange(1, 10):
+            s.send(request)
+            response = s.recv(4096)
+            # cheat, since we know what the body should have
+            if not response.endswith('hello'):
+                response += s.recv(4096)
+            self.assertIn('HTTP/1.1 200 OK', response)
+            self.assertIn('hello', response)
+
+    def _aux_error_path(self, protocol, headers=None):
+        # connect tcp
+        s = self._get_socket()
+
+        request = ('GET / HTTP/1.1\r\n'
+                   'Host: foobar.com\r\n')
+        request += self._headers_to_str(headers)
+        request += '\r\n'
+        for x in xrange(1, 10):
+            s.send(request)
+            response = s.recv(4096)
+            self.assertIn('HTTP/1.1 404 Not Found on Accelerator', response)
+
+    def _aux_error_path_post(self, protocol, headers=None):
+        '''
+        Ensure that sending a request with a body doesn't break the keepalive 
session
+        '''
+        # connect tcp
+        s = self._get_socket()
+
+        request = ('POST / HTTP/1.1\r\n'
+                   'Host: foobar.com\r\n'
+                   'Content-Length: 10\r\n')
+        request += self._headers_to_str(headers)
+        request += '\r\n'
+        request += '1234567890'
+
+        for x in xrange(1, 10):
+            try:
+                s.send(request)
+            except IOError:
+                s = self._get_socket()
+                s.send(request)
+
+            response = s.recv(4096)
+            # Check if client disconnected
+            if response:
+                self.assertIn('HTTP/1.1 404 Not Found on Accelerator', 
response)
+
+
+class BasicTestsOutMixin(object):
+
+    def _aux_KA_origin(self, protocol, headers=None):
+        '''
+        Test that the origin does in fact support keepalive
+        '''
+        conn_id = None
+        with requests.Session() as s:
+            url = '{0}://127.0.0.1:{1}/'.format(protocol, 
self.socket_server.port)
+            for x in xrange(1, 10):
+                ret = s.get(url, verify=False, headers=headers)
+                if not conn_id:
+                    conn_id = ret.text.strip()
+                self.assertEqual(ret.status_code, 200)
+                self.assertEqual(ret.text.strip(), conn_id, "Client reports 
server closed connection")
+
+    def _aux_KA_proxy(self, protocol, headers=None):
+        '''
+        Test that keepalive works through ATS to that origin
+        '''
+        url = '{0}://127.0.0.1:{1}'.format(protocol,
+            
self.configs['records.config']['CONFIG']['proxy.config.http.server_ports'])
+        conn_id = None
+        for x in xrange(1, 10):
+            ret = requests.get(url, verify=False, headers=headers)
+            if not conn_id:
+              conn_id = ret.text.strip()
+            self.assertEqual(ret.status_code, 200)
+            self.assertEqual(ret.text.strip(), conn_id, "Client reports server 
closed connection")
+
+class TimeoutOutMixin(object):
+
+    def _aux_KA_timeout_direct(self, protocol):
+        '''Tests that origin does not timeout using keepalive.'''
+        with requests.Session() as s:
+            url = '{0}://127.0.0.1:{1}/'.format(protocol, 
self.socket_server.port)
+            conn_id = None
+            for x in xrange(0, 3):
+                ret = s.get(url, verify=False)
+                if not conn_id:
+                    conn_id = ret.text.strip()
+                self.assertEqual(ret.text.strip(), conn_id, "Client reports 
server closed connection")
+                time.sleep(3)
+
+    def _aux_KA_timeout_proxy(self, protocol):
+        '''Tests that keepalive timeout is honored through ATS to origin.'''
+        url = '{0}://127.0.0.1:{1}'.format(protocol,
+            
self.configs['records.config']['CONFIG']['proxy.config.http.server_ports'])
+        conn_id = None
+        for x in xrange(0, 3):
+            ret = requests.get(url, verify=False)
+            if not conn_id:
+                conn_id = ret.text.strip()
+            self.assertEqual(ret.text.strip(), conn_id, "Client reports server 
closed connection")
+            time.sleep(3)
+
+
+class OriginMinMaxMixin(object):
+
+    def _aux_KA_min_origin(self, protocol):
+        '''Tests that origin_min_keep_alive_connections is honored.'''
+        url = '{0}://127.0.0.1:{1}'.format(protocol,
+            
self.configs['records.config']['CONFIG']['proxy.config.http.server_ports'])
+        ret = requests.get(url, verify=False)
+        conn_id = ret.text.strip()
+        time.sleep(3)
+        ret = requests.get(url, verify=False)
+        self.assertEqual(ret.text.strip(), conn_id, "Client reports server 
closed connection")
+
+
+class TestKeepAliveInHTTP(tsqa.test_cases.DynamicHTTPEndpointCase, 
helpers.EnvironmentCase, KeepAliveInMixin):
+    @classmethod
+    def setUpEnv(cls, env):
+
+        def hello(request):
+            return 'hello'
+        cls.http_endpoint.add_handler('/exists/', hello)
+
+        cls.configs['remap.config'].add_line('map /exists/ 
http://127.0.0.1:{0}/exists/'.format(cls.http_endpoint.address[1]))
+
+        # only add server headers when there weren't any
+        
cls.configs['records.config']['CONFIG']['proxy.config.http.response_server_enabled']
 = 2
+        
cls.configs['records.config']['CONFIG']['proxy.config.http.keep_alive_enabled_in']
 = 1
+        cls.configs['records.config']['CONFIG']['share_server_session'] = 2
+
+        # set only one ET_NET thread (so we don't have to worry about the 
per-thread pools causing issues)
+        
cls.configs['records.config']['CONFIG']['proxy.config.exec_thread.limit'] = 1
+        
cls.configs['records.config']['CONFIG']['proxy.config.exec_thread.autoconfig'] 
= 0
+
+    def test_working_path(self):
+        self._aux_working_path("http")
+
+    def test_error_path(self):
+        self._aux_error_path("http")
+
+    def test_error_path_post(self):
+        '''
+        Ensure that sending a request with a body doesn't break the keepalive 
session
+        '''
+        self._aux_error_path_post("http")
+
+class TestKeepAliveOriginConnOutHTTP(helpers.EnvironmentCase, 
OriginMinMaxMixin):
+    @classmethod
+    def setUpEnv(cls, env):
+        '''
+        This function is responsible for setting up the environment for this 
fixture
+        This includes everything pre-daemon start
+        '''
+        # create a socket server
+        cls.socket_server = 
tsqa.endpoint.SocketServerDaemon(KeepaliveTCPHandler)
+        cls.socket_server.start()
+        cls.socket_server.ready.wait()
+        cls.configs['remap.config'].add_line('map / 
http://127.0.0.1:{0}/'.format(cls.socket_server.port))
+
+        # only add server headers when there weren't any
+        
cls.configs['records.config']['CONFIG']['proxy.config.http.response_server_enabled']
 = 2
+        
cls.configs['records.config']['CONFIG']['proxy.config.http.keep_alive_enabled_out']
 = 1
+        cls.configs['records.config']['CONFIG']['share_server_session'] = 2
+
+        # set only one ET_NET thread (so we don't have to worry about the 
per-thread pools causing issues)
+        
cls.configs['records.config']['CONFIG']['proxy.config.exec_thread.limit'] = 1
+        
cls.configs['records.config']['CONFIG']['proxy.config.exec_thread.autoconfig'] 
= 0
+
+        # Timeouts
+        
cls.configs['records.config']['CONFIG']['proxy.config.http.keep_alive_no_activity_timeout_out']
 = 1
+        
cls.configs['records.config']['CONFIG']['proxy.config.http.transaction_no_activity_timeout_out']
 = 1
+
+        
cls.configs['records.config']['CONFIG']['proxy.config.http.origin_min_keep_alive_connections']
 = 1
+
+    def test_KA_min_origin(self):
+        '''Tests that origin_min_keep_alive_connections is honored via http.'''
+        self._aux_KA_min_origin("http")
+
+
+class TestKeepAliveOriginConnOutHTTPS(helpers.EnvironmentCase, 
OriginMinMaxMixin):
+    @classmethod
+    def setUpEnv(cls, env):
+        '''
+        This function is responsible for setting up the environment for this 
fixture
+        This includes everything pre-daemon start
+        '''
+         # create a socket server
+        cls.socket_server = 
tsqa.endpoint.SSLSocketServerDaemon(KeepaliveTCPHandler,
+                                             
helpers.tests_file_path('cert.pem'),
+                                             
helpers.tests_file_path('key.pem'))
+        cls.socket_server.start()
+        cls.socket_server.ready.wait()
+        cls.configs['remap.config'].add_line('map / 
https://127.0.0.1:{0}/\n'.format(cls.socket_server.port))
+
+        # only add server headers when there weren't any
+        
cls.configs['records.config']['CONFIG']['proxy.config.http.response_server_enabled']
 = 2
+        
cls.configs['records.config']['CONFIG']['proxy.config.http.keep_alive_enabled_out']
 = 1
+        cls.configs['records.config']['CONFIG']['share_server_session'] = 2
+
+        # set only one ET_NET thread (so we don't have to worry about the 
per-thread pools causing issues)
+        
cls.configs['records.config']['CONFIG']['proxy.config.exec_thread.limit'] = 1
+        
cls.configs['records.config']['CONFIG']['proxy.config.exec_thread.autoconfig'] 
= 0
+        
cls.configs['records.config']['CONFIG']['proxy.config.ssl.number.threads'] = -1
+
+        # Timeouts
+        
cls.configs['records.config']['CONFIG']['proxy.config.http.keep_alive_no_activity_timeout_out']
 = 1
+        
cls.configs['records.config']['CONFIG']['proxy.config.http.transaction_no_activity_timeout_out']
 = 1
+
+        
cls.configs['records.config']['CONFIG']['proxy.config.http.origin_min_keep_alive_connections']
 = 1
+
+    def test_KA_min_origin(self):
+        '''Tests that origin_min_keep_alive_connections is honored via 
https.'''
+        self._aux_KA_min_origin("http")
+
+
+class TestKeepAliveOutHTTP(helpers.EnvironmentCase, BasicTestsOutMixin, 
TimeoutOutMixin):
+    @classmethod
+    def setUpEnv(cls, env):
+        '''
+        This function is responsible for setting up the environment for this 
fixture
+        This includes everything pre-daemon start
+        '''
+        # create a socket server
+        cls.socket_server = 
tsqa.endpoint.SocketServerDaemon(KeepaliveTCPHandler)
+        cls.socket_server.start()
+        cls.socket_server.ready.wait()
+        cls.configs['remap.config'].add_line('map / 
http://127.0.0.1:{0}/'.format(cls.socket_server.port))
+
+        # only add server headers when there weren't any
+        
cls.configs['records.config']['CONFIG']['proxy.config.http.response_server_enabled']
 = 2
+        
cls.configs['records.config']['CONFIG']['proxy.config.http.keep_alive_enabled_out']
 = 1
+        cls.configs['records.config']['CONFIG']['share_server_session'] = 2
+
+        # set only one ET_NET thread (so we don't have to worry about the 
per-thread pools causing issues)
+        
cls.configs['records.config']['CONFIG']['proxy.config.exec_thread.limit'] = 1
+        
cls.configs['records.config']['CONFIG']['proxy.config.exec_thread.autoconfig'] 
= 0
+
+        # Timeouts
+        
cls.configs['records.config']['CONFIG']['proxy.config.http.keep_alive_no_activity_timeout_out']
 = 10
+        
cls.configs['records.config']['CONFIG']['proxy.config.http.transaction_no_activity_timeout_out']
 = 2
+
+    def test_KA_origin(self):
+        '''Test that the origin does in fact support keepalive via http.'''
+        self._aux_KA_origin("http")
+
+    def test_KA_proxy(self):
+        '''Tests that keepalive works through ATS to origin via http.'''
+        self._aux_KA_proxy("http")
+
+    def test_KA_timeout_direct(self):
+        '''Tests that origin does not timeout using keepalive via http.'''
+        self._aux_KA_timeout_direct("http")
+
+    def test_KA_timeout_proxy(self):
+        '''Tests that keepalive timeout is honored through ATS to origin via 
http.'''
+        self._aux_KA_timeout_proxy("http")
+
+
+class TestKeepAliveOutHTTPS(helpers.EnvironmentCase, BasicTestsOutMixin, 
TimeoutOutMixin):
+    @classmethod
+    def setUpEnv(cls, env):
+        '''
+        This function is responsible for setting up the environment for this 
fixture
+        This includes everything pre-daemon start
+        '''
+        # create a socket server
+        cls.socket_server = 
tsqa.endpoint.SSLSocketServerDaemon(KeepaliveTCPHandler,
+                                             
helpers.tests_file_path('cert.pem'),
+                                             
helpers.tests_file_path('key.pem'))
+        cls.socket_server.start()
+        cls.socket_server.ready.wait()
+        cls.configs['remap.config'].add_line('map / 
https://127.0.0.1:{0}/\n'.format(cls.socket_server.port))
+
+        # only add server headers when there weren't any
+        
cls.configs['records.config']['CONFIG']['proxy.config.http.response_server_enabled']
 = 2
+        
cls.configs['records.config']['CONFIG']['proxy.config.http.keep_alive_enabled_out']
 = 1
+        cls.configs['records.config']['CONFIG']['share_server_session'] = 2
+
+        # set only one ET_NET thread (so we don't have to worry about the 
per-thread pools causing issues)
+        
cls.configs['records.config']['CONFIG']['proxy.config.exec_thread.limit'] = 1
+        
cls.configs['records.config']['CONFIG']['proxy.config.exec_thread.autoconfig'] 
= 0
+        
cls.configs['records.config']['CONFIG']['proxy.config.ssl.number.threads'] = -1
+
+        # Timeouts
+        
cls.configs['records.config']['CONFIG']['proxy.config.http.keep_alive_no_activity_timeout_out']
 = 10
+        
cls.configs['records.config']['CONFIG']['proxy.config.http.transaction_no_activity_timeout_out']
 = 2
+
+    def test_KA_origin(self):
+        '''Test that the origin does in fact support keepalive via https.'''
+        self._aux_KA_origin("https")
+
+    def test_KA_proxy(self):
+        '''Tests that keepalive works through ATS to origin via https.'''
+        self._aux_KA_proxy("http")
+
+    def test_KA_timeout_direct(self):
+        '''Tests that origin does not timeout using keepalive via https.'''
+        self._aux_KA_timeout_direct("https")
+
+    def test_KA_timeout_proxy(self):
+        '''Tests that keepalive timeout is honored through ATS to origin via 
https.'''
+        self._aux_KA_timeout_proxy("http")
+
+
+
+# TODO: refactor these tests, these are *very* similar, we should paramatarize 
them
+## Some basic tests for auth_sever_session_private
+class TestKeepAlive_Authorization_private(helpers.EnvironmentCase, 
BasicTestsOutMixin, KeepAliveInMixin):
+    @classmethod
+    def setUpEnv(cls, env):
+
+        cls.socket_server = 
tsqa.endpoint.SocketServerDaemon(KeepaliveTCPHandler)
+        cls.socket_server.start()
+        cls.socket_server.ready.wait()
+        cls.configs['remap.config'].add_line('map / 
http://127.0.0.1:{0}/exists/'.format(cls.socket_server.port))
+
+        # only add server headers when there weren't any
+        
cls.configs['records.config']['CONFIG']['proxy.config.http.response_server_enabled']
 = 2
+        
cls.configs['records.config']['CONFIG']['proxy.config.http.keep_alive_enabled_in']
 = 1
+        cls.configs['records.config']['CONFIG']['share_server_session'] = 2
+
+        # set only one ET_NET thread (so we don't have to worry about the 
per-thread pools causing issues)
+        
cls.configs['records.config']['CONFIG']['proxy.config.exec_thread.limit'] = 1
+        
cls.configs['records.config']['CONFIG']['proxy.config.exec_thread.autoconfig'] 
= 0
+
+        # make auth sessions private
+        
cls.configs['records.config']['CONFIG']['proxy.config.auth_server_session_private']
 = 1
+
+    def test_KA_server(self):
+        '''Tests that keepalive works through ATS to origin via https.'''
+        with self.assertRaises(AssertionError):
+            self._aux_KA_proxy("http", headers={'Authorization': 'Foo'})
+
+    def test_KA_client(self):
+        '''Tests that keepalive works through ATS to origin via https.'''
+        with self.assertRaises(AssertionError):
+            self._aux_KA_working_path_connid("http", headers={'Authorization': 
'Foo'})
+
+
+class TestKeepAlive_Authorization_no_private(helpers.EnvironmentCase, 
BasicTestsOutMixin, KeepAliveInMixin):
+    @classmethod
+    def setUpEnv(cls, env):
+
+        cls.socket_server = 
tsqa.endpoint.SocketServerDaemon(KeepaliveTCPHandler)
+        cls.socket_server.start()
+        cls.socket_server.ready.wait()
+        cls.configs['remap.config'].add_line('map / 
http://127.0.0.1:{0}/exists/'.format(cls.socket_server.port))
+
+        # only add server headers when there weren't any
+        
cls.configs['records.config']['CONFIG']['proxy.config.http.response_server_enabled']
 = 2
+        
cls.configs['records.config']['CONFIG']['proxy.config.http.keep_alive_enabled_in']
 = 1
+        cls.configs['records.config']['CONFIG']['share_server_session'] = 2
+
+        # set only one ET_NET thread (so we don't have to worry about the 
per-thread pools causing issues)
+        
cls.configs['records.config']['CONFIG']['proxy.config.exec_thread.limit'] = 1
+        
cls.configs['records.config']['CONFIG']['proxy.config.exec_thread.autoconfig'] 
= 0
+
+        # make auth sessions private
+        
cls.configs['records.config']['CONFIG']['proxy.config.http.auth_server_session_private']
 = 0
+
+    def test_KA_server(self):
+        '''Tests that keepalive works through ATS to origin via https.'''
+        self._aux_KA_proxy("http", headers={'Authorization': 'Foo'})
+
+    def test_KA_client(self):
+        '''Tests that keepalive works through ATS to origin via https.'''
+        self._aux_KA_working_path_connid("http", headers={'Authorization': 
'Foo'})

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/51ea4aa9/ci/tsqa/tests/test_redirection.py
----------------------------------------------------------------------
diff --git a/ci/tsqa/tests/test_redirection.py 
b/ci/tsqa/tests/test_redirection.py
new file mode 100644
index 0000000..1100dc1
--- /dev/null
+++ b/ci/tsqa/tests/test_redirection.py
@@ -0,0 +1,41 @@
+#  Licensed to the Apache Software Foundation (ASF) under one
+#  or more contributor license agreements.  See the NOTICE file
+#  distributed with this work for additional information
+#  regarding copyright ownership.  The ASF licenses this file
+#  to you under the Apache License, Version 2.0 (the
+#  "License"); you may not use this file except in compliance
+#  with the License.  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.
+
+import requests
+import helpers
+import tsqa.test_cases
+import tsqa.utils
+import tsqa.endpoint
+
+class TestRedirection(helpers.EnvironmentCase, tsqa.test_cases.HTTPBinCase):
+    @classmethod
+    def setUpEnv(cls, env):
+        cls.configs['records.config']['CONFIG'].update({
+            'proxy.config.http.redirection_enabled': 1,
+            'proxy.config.http.number_of_redirections': 10
+        })
+        cls.configs['remap.config'].add_line('map / 
http://127.0.0.1:{0}'.format(cls.http_endpoint.address[1]))
+
+    def test_redirection(self):
+        server_ports = 
self.configs['records.config']['CONFIG']['proxy.config.http.server_ports']
+
+        # By default Requests will perform location redirection
+        # Disable redirection handling with the allow_redirects parameter
+        r = 
requests.get('http://127.0.0.1:{0}/redirect/9'.format(server_ports), 
allow_redirects=False)
+        self.assertEqual(r.status_code, 200)
+
+        r = 
requests.get('http://127.0.0.1:{0}/redirect/10'.format(server_ports), 
allow_redirects=False)
+        self.assertEqual(r.status_code, 302)

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/51ea4aa9/ci/tsqa/tests/test_regressions.py
----------------------------------------------------------------------
diff --git a/ci/tsqa/tests/test_regressions.py 
b/ci/tsqa/tests/test_regressions.py
new file mode 100644
index 0000000..8fec2eb
--- /dev/null
+++ b/ci/tsqa/tests/test_regressions.py
@@ -0,0 +1,82 @@
+'''
+Run the built-in regression tests with experimental build configurations.
+'''
+
+#  Licensed to the Apache Software Foundation (ASF) under one
+#  or more contributor license agreements.  See the NOTICE file
+#  distributed with this work for additional information
+#  regarding copyright ownership.  The ASF licenses this file
+#  to you under the Apache License, Version 2.0 (the
+#  "License"); you may not use this file except in compliance
+#  with the License.  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.
+
+import os
+import sys
+import requests
+import time
+import subprocess
+import logging
+
+import helpers
+import tsqa.test_cases
+import tsqa.utils
+
+log = logging.getLogger(__name__)
+
+class TestRegressions(helpers.EnvironmentCase):
+    '''
+    Run the built-in traffic_server regression test suite.
+    '''
+
+    # NOTE: we need to stop the running Traffic Server in the environment so
+    # that we can start up our own. Make sure to restart it when we are done so
+    # that the EnvironmentCase doesn't get upset.
+
+    @classmethod
+    def setUpClass(cls):
+        super(TestRegressions, cls).setUpClass()
+        cls.environment.stop()
+
+    @classmethod
+    def tearDownClass(cls):
+        cls.environment.start()
+        super(TestRegressions, cls).tearDownClass()
+
+    def test_regressions(self):
+        cmd = [os.path.join(self.environment.layout.bindir, 'traffic_server'), 
'-R', '1']
+        tsqa.utils.run_sync_command(cmd, stdout=subprocess.PIPE, 
stderr=subprocess.STDOUT)
+
+class TestRegressionsReclaimableFreelist(TestRegressions):
+    '''
+    Run the built-in traffic_server regression test suite with
+    --enable-reclaimable-freelist.
+    '''
+    environment_factory = {
+        'configure': { 'enable-reclaimable-freelist': None },
+    }
+
+class TestRegressionsInterimCache(TestRegressions):
+    '''
+    Run the built-in traffic_server regression test suite with
+    --enable-interim-cache.
+    '''
+    environment_factory = {
+        'configure': { 'enable-interim-cache': None },
+    }
+
+class TestRegressionsLinuxNativeAIO(TestRegressions):
+    '''
+    Run the built-in traffic_server regression test suite with
+    --enable-linux-native-aio.
+    '''
+    environment_factory = {
+        'configure': { 'enable-linux-native-aio': None },
+    }

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/51ea4aa9/ci/tsqa/tests/test_remap.py
----------------------------------------------------------------------
diff --git a/ci/tsqa/tests/test_remap.py b/ci/tsqa/tests/test_remap.py
new file mode 100644
index 0000000..aac6e8e
--- /dev/null
+++ b/ci/tsqa/tests/test_remap.py
@@ -0,0 +1,125 @@
+#  Licensed to the Apache Software Foundation (ASF) under one
+#  or more contributor license agreements.  See the NOTICE file
+#  distributed with this work for additional information
+#  regarding copyright ownership.  The ASF licenses this file
+#  to you under the Apache License, Version 2.0 (the
+#  "License"); you may not use this file except in compliance
+#  with the License.  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.
+
+import os
+import requests
+import time
+import logging
+
+import helpers
+
+import tsqa.test_cases
+import tsqa.utils
+import tsqa.endpoint
+
+log = logging.getLogger(__name__)
+
+class TestRemapHTTP(tsqa.test_cases.DynamicHTTPEndpointCase, 
helpers.EnvironmentCase):
+    @classmethod
+    def setUpEnv(cls, env):
+        cls.configs['records.config']['CONFIG'].update({
+            'proxy.config.diags.debug.enabled': 1,
+            'proxy.config.diags.debug.tags': 'url.*',
+        })
+
+        cls.configs['remap.config'].add_line(
+            'map http://www.example.com 
http://127.0.0.1:{0}'.format(cls.http_endpoint.address[1]));
+        cls.configs['remap.config'].add_line(
+            'map http://www.example.com:8080 
http://127.0.0.1:{0}'.format(cls.http_endpoint.address[1]));
+
+        def hello(request):
+            return 'hello'
+        cls.http_endpoint.add_handler('/', hello)
+
+    def test_remap_http(self):
+        s = requests.Session()
+        http_port = 
self.configs['records.config']['CONFIG']['proxy.config.http.server_ports']
+        url = 'http://127.0.0.1:{0}/'.format(http_port)
+
+        ret = s.get(url)
+        self.assertEqual(ret.status_code, 404)
+
+        s.headers.update({'Host': 'www.example.com'})
+        ret = s.get(url)
+        self.assertEqual(ret.status_code, 200)
+
+        s.headers.update({'Host': 'www.example.com:80'})
+        ret = s.get(url)
+        self.assertEqual(ret.status_code, 200)
+
+        s.headers.update({'Host': 'www.example.com:8080'})
+        ret = s.get(url)
+        self.assertEqual(ret.status_code, 200)
+
+        s.headers.update({'Host': 'www.test.com'})
+        ret = s.get(url)
+        self.assertEqual(ret.status_code, 404)
+
+        s.headers.update({'Host': 'www.example.com:1234'})
+        ret = s.get(url)
+        self.assertEqual(ret.status_code, 404)
+
+class TestRemapHTTPS(tsqa.test_cases.DynamicHTTPEndpointCase, 
helpers.EnvironmentCase):
+    @classmethod
+    def setUpEnv(cls, env):
+        # set an SSL port to ATS
+        cls.ssl_port = tsqa.utils.bind_unused_port()[1]
+        
cls.configs['records.config']['CONFIG']['proxy.config.http.server_ports'] += ' 
{0}:ssl'.format(cls.ssl_port)
+        cls.configs['records.config']['CONFIG'].update({
+            'proxy.config.diags.debug.enabled': 1,
+            'proxy.config.diags.debug.tags': 'url.*'
+        })
+
+        cls.configs['remap.config'].add_line(
+                'map https://www.example.com 
http://127.0.0.1:{0}'.format(cls.http_endpoint.address[1]));
+        cls.configs['remap.config'].add_line(
+                'map https://www.example.com:4443 
http://127.0.0.1:{0}'.format(cls.http_endpoint.address[1]));
+        # configure SSL multicert
+        cls.configs['ssl_multicert.config'].add_line(
+                'dest_ip=* 
ssl_cert_name={0}'.format(helpers.tests_file_path('rsa_keys/www.example.com.pem')))
+
+        def hello(request):
+            return 'hello'
+        cls.http_endpoint.add_handler('/', hello)
+
+    def test_remap_https(self):
+        s = requests.Session()
+        url = 'https://127.0.0.1:{0}/'.format(self.ssl_port)
+
+        # We lack of SNI support in requests module, so we do not verify SSL 
certificate here.
+        # ret = s.get(url, verify=(helpers.tests_file_path('certs/ca.crt')))
+        ret = s.get(url, verify=False)
+        self.assertEqual(ret.status_code, 404)
+
+        s.headers.update({'Host': 'www.example.com'})
+        ret = s.get(url, verify=False)
+        self.assertEqual(ret.status_code, 200)
+
+        s.headers.update({'Host': 'www.example.com:443'})
+        ret = s.get(url)
+        self.assertEqual(ret.status_code, 200)
+
+        s.headers.update({'Host': 'www.example.com:4443'})
+        ret = s.get(url)
+        self.assertEqual(ret.status_code, 200)
+
+        s.headers.update({'Host': 'www.test.com'})
+        ret = s.get(url)
+        self.assertEqual(ret.status_code, 404)
+
+        s.headers.update({'Host': 'www.example.com:1234'})
+        ret = s.get(url)
+        self.assertEqual(ret.status_code, 404)

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/51ea4aa9/ci/tsqa/tests/test_spdy_protocol_select.py
----------------------------------------------------------------------
diff --git a/ci/tsqa/tests/test_spdy_protocol_select.py 
b/ci/tsqa/tests/test_spdy_protocol_select.py
new file mode 100644
index 0000000..50fabce
--- /dev/null
+++ b/ci/tsqa/tests/test_spdy_protocol_select.py
@@ -0,0 +1,156 @@
+#  Licensed to the Apache Software Foundation (ASF) under one
+#  or more contributor license agreements.  See the NOTICE file
+#  distributed with this work for additional information
+#  regarding copyright ownership.  The ASF licenses this file
+#  to you under the Apache License, Version 2.0 (the
+#  "License"); you may not use this file except in compliance
+#  with the License.  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.
+
+import os
+import requests
+import time
+import logging
+import subprocess
+
+import helpers
+
+import tsqa.test_cases
+import tsqa.utils
+import tsqa.endpoint
+
+log = logging.getLogger(__name__)
+
+#helper function to get spdycat path
+def which(program):
+    def is_exe(fpath):
+        return os.path.isfile(fpath) and os.access(fpath, os.X_OK)
+    fpath, fname = os.path.split(program)
+    if fpath:
+        if is_exe(program):
+            return program
+    else:
+        for path in os.environ["PATH"].split(os.pathsep):
+            path = path.strip('"')
+            exe_file = os.path.join(path, program)
+            if is_exe(exe_file):
+                return exe_file
+    return None
+
+class TestSPDY(helpers.EnvironmentCase):
+    environment_factory = {
+        'configure': {'enable-spdy': None},
+        'env': {'PKG_CONFIG_PATH': os.getenv("SPDY_PKG_CONFIG_PATH", 
"/opt/spdylay/lib/pkgconfig/")},
+        }
+
+    @classmethod
+    def setUpEnv(cls, env):
+        '''
+        This function is responsible for setting up the environment for this 
fixture
+        This includes everything pre-daemon start
+        '''
+        # set up spdycat
+        cls.client = which('spdycat')
+        if cls.client is None:
+            build_dir = os.environ.get('top_builddir', '../..')
+            log.info('top build_dir = {0}'.format(build_dir))
+            cls.client = '%s/spdylay/src/spdycat' % build_dir
+            if os.path.isfile(cls.client) is False:
+                raise helpers.unittest.SkipTest('Cannot find spdycat. skipping 
test.')
+        
+        log.info('spdycat path = {0}'.format(cls.client))
+
+        # get spdy server ports
+        cls.spdy_port = tsqa.utils.bind_unused_port()[1]
+        log.info('spdy server port = {0}'.format(cls.spdy_port))
+        cls.http_port = tsqa.utils.bind_unused_port()[1]
+        log.info('http server port = {0}'.format(cls.http_port))
+
+        cls.configs['remap.config'].add_line('map / 
https://docs.trafficserver.apache.org/\n')
+        
+        # set only one ET_NET thread (so we don't have to worry about the 
per-thread pools causing issues)
+        
cls.configs['records.config']['CONFIG']['proxy.config.exec_thread.limit'] = 1
+        
cls.configs['records.config']['CONFIG']['proxy.config.exec_thread.autoconfig'] 
= 0
+ 
+        # SPDY configs
+        
cls.configs['records.config']['CONFIG']['proxy.config.http.server_ports'] += ' 
{0}:ssl {1}:proto=http:ssl'.format(cls.spdy_port, cls.http_port)
+        
cls.configs['records.config']['CONFIG']['proxy.config.ssl.server.cert.path'] = 
helpers.tests_file_path('rsa_keys')
+        
+        # configure SSL multicert
+        cls.configs['ssl_multicert.config'].add_line('dest_ip=* 
ssl_cert_name={0}\n'.format(helpers.tests_file_path('rsa_keys/www.example.com.pem')))
+
+    @classmethod
+    def callSpdycat(self, port, path, args):
+        full_args = [self.client,'https://localhost:%d%s' % (port, path)] + 
args
+        self.log.info('full args = {0}'.format(full_args))
+        p = subprocess.Popen(full_args, stdout=subprocess.PIPE,
+            stdin=subprocess.PIPE)
+        self.stdout, self.stderr = p.communicate()
+        return p.returncode
+
+"""
+TODO: re-add spdy2 tests. looks like support here might be lacking some way. 
was not able to get ATS to advertise spdy/2
+even when it was explicitly set with proto=spdy/2
+"""
+class TestSPDYv2(TestSPDY):
+    @classmethod
+    def setUpClass(cls):
+        '''
+        Skip spdy2 tests for now
+        '''
+        raise helpers.unittest.SkipTest('Skipping spdy/2 tests')
+    
+    @classmethod
+    def setUpEnv(cls, env):
+        '''
+        This function is responsible for setting up the environment for this 
fixture
+        This includes everything pre-daemon start
+        ''' 
+        super(TestSPDYv2, cls).setUpEnv(env)
+
+        cls.spdy2_port = tsqa.utils.bind_unused_port()[1]
+        log.info('spdy2 server port = {0}'.format(cls.spdy2_port))
+        # make sure we add port supports spdy2
+        
cls.configs['records.config']['CONFIG']['proxy.config.http.server_ports'] += ' 
{0}:proto=spdy/2:ssl'.format(cls.spdy2_port)
+    
+    def test_SPDY_v2(self):
+        '''
+        Test that the origin does in fact support spdy 2
+        '''
+        self.assertEquals(0, self.callSpdycat(self.spdy2_port, '/', ['-nv', 
'--spdy2'])) #this isn't passing
+        self.assertIn('version=2', self.stdout)
+
+class TestSPDYv3(TestSPDY):
+    def test_SPDY_v3(self):
+        '''
+        Test that the origin does in fact support spdy 3
+        '''
+        self.assertEquals(0, self.callSpdycat(self.spdy_port, '/', ['-nv', 
'--spdy3']))
+        self.assertIn('NPN selected the protocol: spdy/3', self.stdout)
+
+    def test_SPDY_v3_failed_request(self):
+        '''
+        Test that non spdy port won't advertise spdy
+        '''
+        self.assertEquals(1, self.callSpdycat(self.http_port, '/', ['-nv', 
'--spdy3']))
+
+class TestSPDYv3_1(TestSPDY):
+    def test_SPDY_v3_1(self):
+        '''
+        Test that the origin does in fact support spdy 3.1
+        '''
+        self.assertEquals(0, self.callSpdycat(self.spdy_port, '/', ['-nv', 
'--spdy3-1']))
+        self.assertIn('NPN selected the protocol: spdy/3.1', self.stdout)
+
+    def test_SPDY_v3_1_failed_request(self):
+        '''
+        Test that non spdy port won't advertise spdy
+        '''
+        self.assertEquals(1, self.callSpdycat(self.http_port, '/', ['-nv', 
'--spdy3-1']))

Reply via email to