You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@trafficserver.apache.org by jp...@apache.org on 2015/01/28 05:36:58 UTC
[20/50] trafficserver-qa git commit: Replaced sleeps with port
polling.
Replaced sleeps with port polling.
Project: http://git-wip-us.apache.org/repos/asf/trafficserver-qa/repo
Commit: http://git-wip-us.apache.org/repos/asf/trafficserver-qa/commit/a502d378
Tree: http://git-wip-us.apache.org/repos/asf/trafficserver-qa/tree/a502d378
Diff: http://git-wip-us.apache.org/repos/asf/trafficserver-qa/diff/a502d378
Branch: refs/heads/master
Commit: a502d378bd9eca7df0c9b1107d5d789bdbd5da81
Parents: 32fc37c
Author: Joshua Blatt <bl...@yahoo-inc.com>
Authored: Mon Dec 29 11:04:51 2014 -0800
Committer: Joshua Blatt <bl...@yahoo-inc.com>
Committed: Mon Dec 29 11:04:51 2014 -0800
----------------------------------------------------------------------
tests/hello_world_test.py | 10 ++--
tsqa/environment.py | 79 +++++++++++++++------------
tsqa/test_cases.py | 8 ++-
tsqa/utils.py | 118 ++++++++++++++++++++++++++++++++++++++++-
4 files changed, 175 insertions(+), 40 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/trafficserver-qa/blob/a502d378/tests/hello_world_test.py
----------------------------------------------------------------------
diff --git a/tests/hello_world_test.py b/tests/hello_world_test.py
index 2d918ea..302e4b2 100644
--- a/tests/hello_world_test.py
+++ b/tests/hello_world_test.py
@@ -22,22 +22,24 @@ class TestEnvironmentCase(tsqa.test_cases.EnvironmentCase):
# TODO: actually test this, this is currently terrible ;)
def test_daemon(self):
- self.environment.start() # start ATS
- time.sleep(2)
+ self.log.info('Begin test_daemon')
assert self.environment.cop.pid > 0
assert self.environment.cop.returncode is None
- self.environment.stop()
+ self.log.info('End test_daemon')
class TestDynamicHTTPEndpointCase(tsqa.test_cases.DynamicHTTPEndpointCase):
def test_base(self):
+ self.log.info('Begin test_base')
ret = requests.get(self.endpoint_url('/footest'))
self.assertEqual(ret.status_code, 404)
+ self.log.info('End test_base')
def test_endpoint_url(self):
+ self.log.info('Begin test_endpoint_url')
assert self.endpoint_url() == 'http://127.0.0.1:{0}'.format(self.http_endpoint.address[1])
assert self.endpoint_url('/foo') == 'http://127.0.0.1:{0}/foo'.format(self.http_endpoint.address[1])
-
+ self.log.info('End test_endpoint_url')
if __name__ == "__main__":
unittest.main()
http://git-wip-us.apache.org/repos/asf/trafficserver-qa/blob/a502d378/tsqa/environment.py
----------------------------------------------------------------------
diff --git a/tsqa/environment.py b/tsqa/environment.py
index cd5b747..03c1396 100644
--- a/tsqa/environment.py
+++ b/tsqa/environment.py
@@ -3,8 +3,9 @@ import tempfile
import os
import copy
import shutil
-import json
-
+import tsqa.utils
+import logging
+import sys
import tsqa.configs
import tsqa.utils
@@ -28,7 +29,7 @@ class EnvironmentFactory(object):
# TODO: ensure this directory exists? (and is git?)
self.source_dir = source_dir
-
+ self.log = tsqa.utils.get_logger()
self.env_cache_dir = env_cache_dir # base directory for environment caching
if default_configure is not None:
@@ -45,13 +46,20 @@ class EnvironmentFactory(object):
'''
Autoreconf to make the configure script
'''
+
+ kwargs = {
+ 'cwd': self.source_dir,
+ 'env': self.default_env,
+ 'stdout': subprocess.PIPE,
+ 'stderr': subprocess.PIPE
+ }
+
+ if self.log.isEnabledFor(logging.DEBUG):
+ kwargs['stdout'] = sys.stdout.fileno()
+ kwargs['stderr'] = sys.stderr.fileno()
+
# run autoreconf in source tree
- tsqa.utils.run_sync_command(['autoreconf', '-if'],
- cwd=self.source_dir,
- env=self.default_env,
- stdout=subprocess.PIPE,
- stderr=subprocess.PIPE,
- )
+ tsqa.utils.run_sync_command(['autoreconf', '-if'], **kwargs)
@property
def source_hash(self):
@@ -114,39 +122,34 @@ class EnvironmentFactory(object):
del env[blacklisted_key]
key = self._get_key(configure, env)
- # TODO: remove
- print 'Key is:', key, 'args are:', configure, env
+ self.log.debug('Key is: %s, args are: %s %s' % (key, configure, env))
# if we don't have it built already, lets build it
if key not in self.environment_stash:
self.autoreconf()
builddir = tempfile.mkdtemp()
+ kwargs = {
+ 'cwd': builddir,
+ 'env': env,
+ 'stdout': subprocess.PIPE,
+ 'stderr': subprocess.PIPE
+ }
+
+ if self.log.isEnabledFor(logging.DEBUG):
+ kwargs['stdout'] = sys.stdout.fileno()
+ kwargs['stderr'] = sys.stderr.fileno()
+
# configure
args = [os.path.join(self.source_dir, 'configure'), '--prefix=/'] + tsqa.utils.configure_list(configure)
- tsqa.utils.run_sync_command(args,
- cwd=builddir,
- env=env,
- stdout=subprocess.PIPE,
- stderr=subprocess.PIPE,
- )
+ tsqa.utils.run_sync_command(args, **kwargs)
# make
- tsqa.utils.run_sync_command(['make', '-j'],
- cwd=builddir,
- env=env,
- stdout=subprocess.PIPE,
- stderr=subprocess.PIPE,
- )
+ tsqa.utils.run_sync_command(['make', '-j'], **kwargs)
installdir = tempfile.mkdtemp(dir=self.env_cache_dir)
# make install
- tsqa.utils.run_sync_command(['make', 'install', 'DESTDIR={0}'.format(installdir)],
- cwd=builddir,
- env=env,
- stdout=subprocess.PIPE,
- stderr=subprocess.PIPE,
- )
+ tsqa.utils.run_sync_command(['make', 'install', 'DESTDIR={0}'.format(installdir)], **kwargs)
shutil.rmtree(builddir) # delete builddir, not useful after install
# stash the env
@@ -184,6 +187,7 @@ class Layout:
def __init__(self, prefix):
self.prefix = prefix
+ self.log = tsqa.utils.get_logger()
def __getattr__(self, name):
# Raise an error for suffixes we don't know about
@@ -237,8 +241,8 @@ class Environment:
stdout=logfile,
stderr=logfile,
)
- import time
- time.sleep(3) # TODO: wait or the process to listen?
+ tsqa.utils.poll_interfaces(self.hostports)
+
# TODO: better checking...
self.cop.poll()
if self.cop.returncode is not None:
@@ -248,7 +252,9 @@ class Environment:
"""
Initialize a new Environment.
"""
+ self.log = tsqa.utils.get_logger()
self.cop = None
+ self.hostports = []
if layout:
self.layout = layout
else:
@@ -292,6 +298,10 @@ class Environment:
else:
os.chmod(dirname, 0777)
+ http_server_port = tsqa.utils.bind_unused_port()[1]
+ manager_mgmt_port = tsqa.utils.bind_unused_port()[1]
+ self.hostports = [('127.0.0.1', http_server_port), ('127.0.0.1', manager_mgmt_port)]
+
# overwrite a few things that need to be changed to have a unique env
records = tsqa.configs.RecordsConfig(os.path.join(self.layout.sysconfdir, 'records.config'))
records['CONFIG'].update({
@@ -301,8 +311,8 @@ class Environment:
'proxy.config.bin_path': self.layout.bindir,
'proxy.config.log.logfile_dir': self.layout.logdir,
'proxy.config.local_state_dir': self.layout.runtimedir,
- 'proxy.config.http.server_ports': str(tsqa.utils.bind_unused_port()[1]), # your own listen port
- 'proxy.config.process_manager.mgmt_port': tsqa.utils.bind_unused_port()[1], # your own listen port
+ 'proxy.config.http.server_ports': str(http_server_port), # your own listen port
+ 'proxy.config.process_manager.mgmt_port': manager_mgmt_port, # your own listen port
})
records.write()
@@ -319,12 +329,15 @@ class Environment:
self.layout = Layout(None)
def start(self):
+ self.log.debug("Starting traffic cop")
assert(os.path.isfile(os.path.join(self.layout.sysconfdir, 'records.config')))
self.__exec_cop()
+ self.log.debug("Started traffic cop: %s", self.cop)
# TODO: more graceful stop?
# TODO: raise exception when you call stop when its not started?
def stop(self):
+ self.log.debug("Killing traffic cop: %s", self.cop)
if self.cop is not None:
self.cop.kill()
self.cop.terminate() # TODO: remove?? or wait...
http://git-wip-us.apache.org/repos/asf/trafficserver-qa/blob/a502d378/tsqa/test_cases.py
----------------------------------------------------------------------
diff --git a/tsqa/test_cases.py b/tsqa/test_cases.py
index d7ba75a..cb1ef55 100644
--- a/tsqa/test_cases.py
+++ b/tsqa/test_cases.py
@@ -10,7 +10,6 @@ unittest = tsqa.utils.import_unittest()
import os
-
# Example environment case
class EnvironmentCase(unittest.TestCase):
'''
@@ -25,6 +24,9 @@ class EnvironmentCase(unittest.TestCase):
# call parent constructor
super(EnvironmentCase, cls).setUpClass()
+ # get a logger
+ cls.log = tsqa.utils.get_logger()
+
# get an environment
cls.environment = cls.getEnv()
@@ -68,6 +70,7 @@ class EnvironmentCase(unittest.TestCase):
if cls.environment.cop is not None and not cls.environment.running:
raise Exception('ATS died during the test run')
# stop ATS
+
cls.environment.stop()
# call parent destructor
@@ -89,6 +92,9 @@ class DynamicHTTPEndpointCase(unittest.TestCase):
'''
@classmethod
def setUpClass(cls, port=0):
+ # get a logger
+ cls.log = tsqa.utils.get_logger()
+
cls.http_endpoint = tsqa.endpoint.DynamicHTTPEndpoint(port=port)
cls.http_endpoint.start()
http://git-wip-us.apache.org/repos/asf/trafficserver-qa/blob/a502d378/tsqa/utils.py
----------------------------------------------------------------------
diff --git a/tsqa/utils.py b/tsqa/utils.py
index f58a2bd..d522f66 100644
--- a/tsqa/utils.py
+++ b/tsqa/utils.py
@@ -4,6 +4,117 @@ import json
import sys
import subprocess
import socket
+import logging
+import time
+
+tsqa_logger = None
+tsqa_log_level = logging.INFO
+tsqa_log_levels = {
+ 'CRITICAL': logging.CRITICAL,
+ 'ERROR': logging.ERROR,
+ 'WARN': logging.WARNING,
+ 'WARNING': logging.WARNING,
+ 'INFO': logging.INFO,
+ 'DEBUG': logging.DEBUG,
+ 'NOTSET': logging.NOTSET
+}
+
+def set_log_level(log_level):
+ '''
+ Set the global log level (override with env var TSQA_LOG_LEVEL). Must be called
+ before first get_logger()
+ '''
+
+ global tsqa_log_level
+ tsqa_log_level = log_level
+
+def get_log_level():
+ '''
+ Get the global log level (override with env var TSQA_LOG_LEVEL).
+ '''
+
+ if os.environ.has_key('TSQA_LOG_LEVEL'):
+ log_level = os.environ['TSQA_LOG_LEVEL'].upper()
+
+ if tsqa_log_levels.has_key(log_level):
+ return tsqa_log_levels[log_level]
+
+ return tsqa_log_level
+
+def set_logger(logger):
+ '''
+ Set/replace the global logger
+ '''
+
+ global tsqa_logger
+ tsqa_logger = logger
+
+def get_logger():
+ '''
+ Get the global logger
+ '''
+
+ global tsqa_logger
+
+ if tsqa_logger:
+ return tsqa_logger
+
+ tsqa_logger = logging.getLogger()
+ tsqa_logger.setLevel(get_log_level())
+ handler = logging.StreamHandler()
+ handler.setFormatter(logging.Formatter("%(levelname)s %(asctime)-15s - %(message)s"))
+ tsqa_logger.addHandler(handler)
+
+ return tsqa_logger
+
+def poll_interfaces(hostports, **kwargs):
+ ''' Block until we can successfully connect to all ports or timeout
+
+ :param hostports:
+ :param kwargs: optional timeout_sec
+ '''
+
+ connect_timeout_sec = 1
+ poll_sleep_sec = 1
+
+ if kwargs.has_key('timeout_sec'):
+ timeout = time.time() + kwargs['timeout_sec']
+ else:
+ timeout = time.time() + 5
+
+ hostports = hostports[:] # don't modify the caller's hostports
+
+ while timeout > time.time():
+ for hostport in hostports[:]: # don't modify our hostports copy during iteration
+ hostname = hostport[0]
+ port = hostport[1]
+
+ if get_logger().isEnabledFor(logging.DEBUG):
+ get_logger().debug("Checking interface '%s:%d'", hostname, port)
+
+ # This supports IPv6
+
+ try:
+ s = socket.create_connection((hostname, port), timeout=connect_timeout_sec)
+ s.close()
+ hostports.remove(hostport)
+
+ if get_logger().isEnabledFor(logging.DEBUG):
+ get_logger().debug("Interface '%s:%d' is up", hostname, port)
+ except:
+ pass
+
+ if not hostports:
+ break
+
+ time.sleep(poll_sleep_sec)
+
+ if hostports:
+ raise Exception("Timeout waiting for interfaces: {0}".format(
+ reduce(lambda x, y: str(x) + ',' + str(y), hostports)))
+
+ if get_logger().isEnabledFor(logging.DEBUG):
+ get_logger().debug("All interfaces are up")
# TODO: test
def import_unittest():
@@ -37,9 +148,12 @@ def run_sync_command(*args, **kwargs):
p = subprocess.Popen(*args, **kwargs)
stdout, stderr = p.communicate()
if p.returncode != 0:
- raise Exception('Error running: {0}\n{1}'.format(args[0], stderr))
- return stdout, stderr
+ if stderr:
+ raise Exception('Error {0} running: {1}\n{2}'.format(p.returncode, args[0], stderr))
+ else:
+ raise Exception('Error {0} running: {1}'.format(p.returncode, args[0]))
+ return stdout, stderr
def merge_dicts(*args):
'''