You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@trafficserver.apache.org by ja...@apache.org on 2015/04/30 22:39:49 UTC

[2/4] trafficserver git commit: Remove old tsqa, and replace it with the new python based one.

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/51ea4aa9/ci/tsqa/functions
----------------------------------------------------------------------
diff --git a/ci/tsqa/functions b/ci/tsqa/functions
deleted file mode 100644
index f839108..0000000
--- a/ci/tsqa/functions
+++ /dev/null
@@ -1,303 +0,0 @@
-#! /usr/bin/env bash
-
-#  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.
-
-NCPU=${NCPU:-$(( $(getconf _NPROCESSORS_ONLN) * 2 ))} # Numer of CPUs to build with
-PORT=${PORT:-9090}                                    # Initial listen port for Traffic Server
-VALGRIND=${VALGRIND:-N}                               # Whether to run under valgrind
-TMPDIR=${TMPDIR:-/tmp}                                # Scratch directory for test instance construction
-
-TSQA_FAIL=0                                         # Test failure count
-TSQA_TESNAME=${TSQA_TESTNAME:-tsqa}                 # Name of current test
-TSQA_ROOT=${TSQA_ROOT:-/tmp/$TSQA_TESTNAME.$RANDOM} # Filesystem root for current test
-TSQA_TSXS=${TSQA_TSXS:-tsxs}
-
-# Print a log message/
-msg() {
-  echo "MSG:" "$@"
-}
-
-msgwait() {
-  local secs="$1"
-  shift
-
-  echo "MSG: waiting ${secs}s" "$@"
-  sleep $secs
-}
-
-# Print a failure message and increment the failure count.
-fail() {
-  TSQA_FAIL=$(($TSQA_FAIL + 1))
-  echo "FAIL:" "$@" 1>&2
-}
-
-# Fail and exit.
-fatal() {
-  TSQA_FAIL=$(($TSQA_FAIL + 1))
-  echo "FATAL:" "$@" 1>&2
-  exit $TSQA_FAIL
-}
-
-# Run a command and silence any output on stderr.
-quiet() {
-  "$@" 2>/dev/null
-}
-
-# Run a command with all output redirected to the pest log file.
-logexec() {
-  echo "$@" >> "$TSQA_ROOT/$TSQA_TESTNAME.log" 2>&1
-  "$@" >> "$TSQA_ROOT/$TSQA_TESTNAME.log" 2>&1
-}
-
-tsxs() {
-  $TSQA_TSXS "$@"
-}
-
-tsexec() {
-  local cmd="$1"
-  local run
-  shift
-
-  case $VALGRIND in
-    y|yes|Y|YES|1) run="valgrind --trace-children=yes --trace-children-skip=env env" ;;
-    *) run=env ;;
-  esac
-
-  # XXX enabling MallocStackLogging on all processes is annoying
-  # because it logs 3 lines to stderr every time. We generally only
-  # want leaks detection on traffic_server, so this is a bit of a
-  # waste ...
-
-  # MALLOC_CHECK_=2 => enable glibc malloc checking, abort on error
-  # MallocStackLogging=1 => record OS X malloc stacks for leak checking
-  $run \
-  MALLOC_CHECK_=2 \
-  MallocErrorAbort=1 \
-  TS_ROOT=$TSQA_ROOT \
-    $(bindir)/$cmd "$@"
-}
-
-reconfigure() {
-  local srcdir="$1"
-  msg running autoreconf in $srcdir ...
-  (
-    cd "$srcdir"
-    autoreconf -i
-  ) > autoreconf.log 2>&1
-}
-
-install () {
-  [[ -d $BUILD ]] && rm -rf $BUILD
-  [[ -d $PREFIX ]] && rm -rf $PREFIX
-
-  msg installing ...
-  mkdir -p $BUILD && (
-    cd $BUILD
-    $SRC/configure \
-      --prefix=$PREFIX \
-      --with-user=$(id -un) \
-      --enable-debug \
-      CCFLAGS=-O0 CXXFLAGS=-O0
-    make -j $NCPU && make install
-  ) > /dev/null
-
-  msg installed to $PREFIX
-}
-
-logdir() {
-  local prefix=$(tsxs -q PREFIX)
-  tsxs -q LOGDIR | sed -es+$prefix/++
-}
-
-runtimedir() {
-  local prefix=$(tsxs -q PREFIX)
-  tsxs -q RUNTIMEDIR | sed -es+$prefix/++
-}
-
-sysconfdir() {
-  local prefix=$(tsxs -q PREFIX)
-  tsxs -q SYSCONFDIR | sed -es+$prefix/++
-}
-
-bindir() {
-  tsxs -q BINDIR
-}
-
-# pidof(name): echo the pid of the given process name
-pidof() {
-  case "$1" in
-  cop|manager|server);;
-  *) fatal no such process name: $1
-  esac
-  quiet cat $TSQA_ROOT/$(runtimedir)/${1}.lock
-}
-
-# alive(name): Test whether the process "name" is alive.
-alive() {
-  local pid=$(pidof $1)
-  if [[ ! -z "$pid" ]] ; then
-    quiet kill -0 $pid
-    return $?
-  fi
-
-  false
-}
-
-# Start up Traffic Server. Test for all the processes so that we have a better
-# chance of delaying the test until traffic_server is ready.
-startup() {
-  local log=$TSQA_ROOT/$(logdir)/cop.log
-  ( tsexec traffic_cop --stdout > $log )&
-  for proc in cop manager server; do
-    for i in $(seq 10) ; do
-      alive $proc && msg $proc is alive && break
-      sleep 1
-    done
-  done
-
-  # And a final sleep to let traffic_server come up ...
-  sleep 2
-}
-
-# Shut down Traffic Server.
-shutdown() {
-
-  # Quick'n'dirty cleanup of background jobs.
-  jobs -p | while read pid ; do
-    kill $pid
-  done
-
-  local pid=$(pidof cop)
-  if [[ -z "$pid" ]] ; then
-    return
-  fi
-
-# XXX If we are on Darwin, we can check the traffic_server for leaks before shutting down, but
-# we really only want to do this for traffic_server ... or we should sink the output to the test
-# log and fail on the exit status.
-
-#  if [ -x /usr/bin/leaks ]; then
-#    msg checking for leaks ...
-#    /usr/bin/leaks $(pidof server)
-#  fi
-
-  msg shutting down ...
-  while quiet kill -0 $pid ; do
-    quiet kill -TERM $pid
-    pid=$(pidof cop)
-    if [[ -z "$pid" ]] ; then
-      return
-    fi
-  done
-
-  exit $TSQA_FAIL
-}
-
-restart() {
-  local pid=$(pidof cop)
-  if [[ -z "$pid" ]] ; then
-    return
-  fi
-
-  msg shutting down ...
-  while quiet kill -0 $pid ; do
-    quiet kill -TERM $pid
-    pid=$(pidof cop)
-    if [[ -z "$pid" ]] ; then
-      return
-    fi
-  done
-
-  startup
-}
-
-# Test for Traffic Server crash logs.
-crash() {
-  local outfile="$TSQA_ROOT/$(logdir)/traffic.out"
-
-  msg checking for crashes ...
-  for i in $(seq 10); do
-    sleep 1
-    [[ -e $outfile ]] && \
-      grep -a -A 10 "STACK TRACE" $outfile && \
-      fail detected a crash
-  done
-}
-
-# Bootstrap a TSQA test root. The result of this is an independent test root
-# that contains all the variable parts of a traffic server configuration, while
-# referring to the parent installation for the actual test binaries.
-bootstrap() {
-  local prefix=$(tsxs -q PREFIX)
-  local sysconfdir=$(tsxs -q SYSCONFDIR | sed -es+$prefix/++)
-  local dir
-  local userid=${SUDO_USER:-$(whoami)}
-
-  # Create runtime directories in the test root.
-  for dir in SYSCONFDIR LOCALSTATEDIR RUNTIMEDIR LOGDIR ; do
-    local p=$(tsxs -q $dir | sed -es+$prefix/++)
-    mkdir -p $TSQA_ROOT/$p
-  done
-
-  # Copy config across
-  cp -r $(tsxs -q SYSCONFDIR)/*.{config,xml} $TSQA_ROOT/$sysconfdir
-
-  # Delete any config variables we are about to set.
-  sed -i.orig \
-    -e/proxy.config.body_factory.template_sets_dir/d \
-    -e/proxy.config.plugin.plugin_dir/d \
-    -e/proxy.config.bin_path/d \
-    -e/proxy.config.admin.user_id/d \
-    -e/proxy.config.diags/d \
-    -e/proxy.config.http.server_ports/d \
-    -e/proxy.config.config_update_interval_ms/d \
-    $TSQA_ROOT/$sysconfdir/records.config || fatal failed to initialize records.config
-
-  cat >> $TSQA_ROOT/$sysconfdir/records.config <<EOF
-CONFIG proxy.config.bin_path STRING $(tsxs -q BINDIR)
-CONFIG proxy.config.plugin.plugin_dir STRING $(tsxs -q LIBEXECDIR)
-CONFIG proxy.config.body_factory.template_sets_dir STRING $(tsxs -q SYSCONFDIR)/body_factory
-
-CONFIG proxy.config.admin.user_id STRING $userid
-CONFIG proxy.config.http.server_ports STRING $PORT
-
-# Flush config updates every 0.5s so that we don't have to sleep so long making config changes.
-CONFIG proxy.config.config_update_interval_ms INT 500
-
-# Send all diagnostics to both traffic.out and diags.log.
-CONFIG proxy.config.diags.output.diag STRING OL
-CONFIG proxy.config.diags.output.debug STRING OL
-CONFIG proxy.config.diags.output.status STRING OL
-CONFIG proxy.config.diags.output.note STRING OL
-CONFIG proxy.config.diags.output.warning STRING OL
-CONFIG proxy.config.diags.output.error STRING OL
-CONFIG proxy.config.diags.output.fatal STRING OL
-CONFIG proxy.config.diags.output.alert STRING OL
-CONFIG proxy.config.diags.output.emergency STRING OL
-
-CONFIG proxy.config.diags.debug.enabled INT 1
-CONFIG proxy.config.diags.debug.tags STRING NULL
-CONFIG proxy.config.diags.show_location INT 1
-EOF
-
-  chown -R "$userid" $TSQA_ROOT
-
-  msg bootstrapped Traffic Server into $TSQA_ROOT
-  tsexec traffic_layout
-}
-
-# vim: set sw=2 ts=2 et :

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/51ea4aa9/ci/tsqa/requirements.txt
----------------------------------------------------------------------
diff --git a/ci/tsqa/requirements.txt b/ci/tsqa/requirements.txt
new file mode 100644
index 0000000..5897503
--- /dev/null
+++ b/ci/tsqa/requirements.txt
@@ -0,0 +1,6 @@
+# requirements for the python virtualenv
+
+# TODO: pin a specific version
+https://github.com/apache/trafficserver-qa/archive/master.zip
+pyyaml
+pyOpenSSL

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/51ea4aa9/ci/tsqa/run_all.sh
----------------------------------------------------------------------
diff --git a/ci/tsqa/run_all.sh b/ci/tsqa/run_all.sh
deleted file mode 100755
index d2f04f2..0000000
--- a/ci/tsqa/run_all.sh
+++ /dev/null
@@ -1,85 +0,0 @@
-#!/bin/sh
-#
-#  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.
-
-OK=()
-FAIL=()
-EXCLUDE=()
-STATUS=0
-
-# Produce a help page
-do_help() {
-    echo "run_all.sh: Run all TSQA tests"
-    echo
-    echo "Options:"
-    echo "	-e	Exclude the given test"
-    echo "	-h	Show this help page"
-}
-
-# Parse the arguments
-while getopts "e:" opt; do
-  case $opt in
-      e)
-	  EXCLUDE+=($OPTARG)
-	  ;;
-      \?|h)
-	  do_help
-	  exit 1
-	  ;;
-  esac
-done
-
-
-# Run all tests, record the results
-for test in test-*; do
-    run_it=1
-    for ex in ${EXCLUDE[@]}; do
-	echo $ex
-	if [ "$ex" == "$test" ]; then
-	    run_it=0
-	    break
-	fi
-    done
-    if [ $run_it -ne 0 ]; then
-	echo "--> Starting test: $test"
-	./${test}
-	res=$?
-	if [ $res != 0 ]; then
-	    echo "Failure: ${test}"
-	    FAIL+=(${test})
-	    STATUS=1
-	else
-	    echo "Success: ${test}"
-	    OK+=(${test})
-	fi
-    fi
-done
-
-
-# Print out a results summary
-echo
-echo
-echo "RESULT SUMMARY"
-echo "=============="
-for t in ${OK[@]}; do
-    echo "$t	...OK"
-done
-for t in ${FAIL[@]}; do
-    echo "$t	...FAIL"
-done
-
-exit ${STATUS}

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/51ea4aa9/ci/tsqa/test-bootstrap
----------------------------------------------------------------------
diff --git a/ci/tsqa/test-bootstrap b/ci/tsqa/test-bootstrap
deleted file mode 100755
index 4f817b4..0000000
--- a/ci/tsqa/test-bootstrap
+++ /dev/null
@@ -1,41 +0,0 @@
-#! /usr/bin/env bash
-
-#  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.
-
-TSQA_TSXS=${TSQA_TSXS:-/opt/ats/bin/tsxs}
-TSQA_TESTNAME=$(basename $0)
-source $(dirname $0)/functions
-
-# This test verifies that we can start Traffic Server in the test root. It is primarily
-# intended as a trivial payload to test the TSQA harness.
-check() {
-
-  msg waiting ...
-  sleep 2
-}
-
-bootstrap
-
-# If Traffic Server is not up, bring it up ...
-alive cop || startup || fatal unable to start Traffic Server
-trap shutdown 0 EXIT
-
-check
-
-exit $TSQA_FAIL
-
-# vim: set sw=2 ts=2 et :

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/51ea4aa9/ci/tsqa/test-log-configuration
----------------------------------------------------------------------
diff --git a/ci/tsqa/test-log-configuration b/ci/tsqa/test-log-configuration
deleted file mode 100755
index 3393c23..0000000
--- a/ci/tsqa/test-log-configuration
+++ /dev/null
@@ -1,68 +0,0 @@
-#! /usr/bin/env bash
-
-#  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.
-
-COUNT=${COUNT:-10}
-TSQA_TSXS=${TSQA_TSXS:-/opt/ats/bin/tsxs}
-TSQA_TESTNAME=$(basename $0)
-source $(dirname $0)/functions
-
-# Make up an arbitratry URL to generate error logs. We use the loopback address
-# number because I've seen "localhost" resolve to an IPv6 address. That sucked.
-URL=http://127.0.0.1:$PORT
-
-# This test verifies that online reloading of the logging configuration
-# does not crash Traffic Server.
-check() {
-  local logdir=$(logdir)
-
-  for i in $(seq $COUNT) ; do
-    msg check $i ...
-    curl --silent --show-error -o /dev/null -H "Host: not there" $URL
-    tsexec traffic_line -s proxy.config.diags.debug.tags -v 'log-.*'
-    tsexec traffic_line -s proxy.config.diags.debug.enabled -v 1
-    tsexec traffic_line -x
-    msgwait 2
-    curl --silent --show-error -o /dev/null -H "Host: not there" $URL
-    # Set a harmless proxy.config.log.hostname to trigger a config reload ...
-    tsexec traffic_line -s proxy.config.log.hostname -v jpeach-test-$$-$i
-    tsexec traffic_line -s proxy.config.log.search_top_sites -v $i
-    tsexec traffic_line -x
-    msgwait 2
-    curl --silent --show-error -o /dev/null -H "Host: not there" $URL
-    crash
-
-    # Verify that we have all the error logs that we expect.
-    for logfile in error.log diags.log manager.log traffic.out ; do
-      [[ -e $TSQA_ROOT/$logdir/$logfile ]] || fatal $logfile is missing
-    done
-
-  done
-}
-
-bootstrap
-
-# If Traffic Server is not up, bring it up ...
-alive cop || startup || fatal unable to start Traffic Server
-trap shutdown 0 EXIT
-
-msgwait 6
-check
-
-exit $TSQA_FAIL
-
-# vim: set sw=2 ts=2 et :

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/51ea4aa9/ci/tsqa/test-log-refcounting
----------------------------------------------------------------------
diff --git a/ci/tsqa/test-log-refcounting b/ci/tsqa/test-log-refcounting
deleted file mode 100755
index 41bd312..0000000
--- a/ci/tsqa/test-log-refcounting
+++ /dev/null
@@ -1,112 +0,0 @@
-#! /usr/bin/env bash
-
-#  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.
-
-TSQA_TSXS=${TSQA_TSXS:-/opt/ats/bin/tsxs}
-TSQA_TESTNAME=$(basename $0)
-source $(dirname $0)/functions
-
-COUNT=${COUNT:-100}
-SERVER_PORT=${SERVER_PORT:-4000}
-RELOAD_INTERVAL_SECS=${RELOAD_INTERVAL_SECS:-30}
-
-bootstrap
-
-# Force a logging subsystem reload.
-reload() {
-  while sleep $RELOAD_INTERVAL_SECS ; do
-    msg reloading logging configuration
-    tsexec traffic_line -s proxy.config.log.hostname -v "$(date)"
-    tsexec traffic_line -x
-  done
-}
-
-if [ ! -x $(bindir)/jtest ] ; then
-  fatal "missing jtest program; rebuild with --enable-test-tools"
-fi
-
-cat >$TSQA_ROOT/$(sysconfdir)/remap.config <<REMAP
-map http://jtest.trafficserver.apache.org:$SERVER_PORT http://127.0.0.1:$SERVER_PORT
-REMAP
-
-# Configure the tcpinfo plugin so that we have some API log objects.
-cat >$TSQA_ROOT/$(sysconfdir)/plugin.config <<REMAP
-tcpinfo.so --log-file=tcpinfo1 --hooks=ssn_start,txn_start,send_resp_hdr,ssn_close,txn_close --log-level=2
-tcpinfo.so --log-file=tcpinfo2 --hooks=ssn_start,txn_start,send_resp_hdr,ssn_close,txn_close --log-level=2
-tcpinfo.so --log-file=tcpinfo3 --hooks=ssn_start,txn_start,send_resp_hdr,ssn_close,txn_close --log-level=2
-tcpinfo.so --log-file=tcpinfo4 --hooks=ssn_start,txn_start,send_resp_hdr,ssn_close,txn_close --log-level=2
-REMAP
-
-# If Traffic Server is not up, bring it up ...
-alive cop || startup || fatal unable to start Traffic Server
-trap shutdown 0 EXIT
-
-# Wait for traffic_manager to start.
-alive manager
-alive server
-msgwait 2
-
-# Logging configuration ...
-tsexec traffic_line -s proxy.config.log.max_space_mb_for_logs -v 10
-tsexec traffic_line -s proxy.config.log.max_space_mb_for_orphan_logs -v 10
-tsexec traffic_line -s proxy.config.log.squid_log_enabled -v 1
-tsexec traffic_line -s proxy.config.log.squid_log_is_ascii -v 1
-# Roll every megabyte ...
-tsexec traffic_line -s proxy.config.log.rolling_interval_sec -v 60
-tsexec traffic_line -s proxy.config.log.rolling_size_mb -v 1
-# Don't declare log space exhausted until there is < 1MB free.
-tsexec traffic_line -s proxy.config.log.max_space_mb_headroom -v 1
-# Flush log buffers every second.
-tsexec traffic_line -s proxy.config.log.max_secs_per_buffer -v 1
-
-# Enable logging diagnostics for test debugging. If you enable this
-# for the test itself, the diagnostics log will exhaust all the logging
-# space and everything will go to hell.
-#tsexec traffic_line -s proxy.config.diags.debug.tags -v log
-
-# The sleep is needed to let Traffic Server schedule the config change.
-msgwait 4 to restart with updated logging configuration
-# XXX: this needs a full bounce
-tsexec traffic_line -L
-
-# Wait for traffic_manager to start.
-alive manager
-alive server
-msgwait 10
-
-msg starting config reload every $RELOAD_INTERVAL_SECS seconds
-reload&
-
-for i in $(seq $COUNT) ; do
-  msg $(bindir)/jtest --proxy_port $PORT --proxy_host 127.0.0.1 \
-    --server_port $SERVER_PORT --server_host jtest.trafficserver.apache.org \
-    --clients 10 --test_time 60
-  $(bindir)/jtest --proxy_port $PORT --proxy_host 127.0.0.1 \
-    --server_port $SERVER_PORT --server_host jtest.trafficserver.apache.org \
-    --clients 10 --test_time 60
-
-  if [ -r $(logdir)/squid.log ]; then
-    fatal squid.log is missing
-  fi
-
-  # Check for a crash ...
-  crash
-done
-
-exit $TSQA_FAIL
-
-# vim: set sw=2 ts=2 et :

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/51ea4aa9/ci/tsqa/test-multicert-loading
----------------------------------------------------------------------
diff --git a/ci/tsqa/test-multicert-loading b/ci/tsqa/test-multicert-loading
deleted file mode 100755
index cc0e49e..0000000
--- a/ci/tsqa/test-multicert-loading
+++ /dev/null
@@ -1,81 +0,0 @@
-#! /usr/bin/env bash
-
-#  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.
-
-# test-multicert-loading: test loading large numbers of SSL certificates.
-
-TSQA_TSXS=${TSQA_TSXS:-/opt/ats/bin/tsxs}
-TSQA_TESTNAME=$(basename $0)
-source $(dirname $0)/functions
-
-bootstrap
-
-# If Traffic Server is not up, bring it up ...
-alive cop || startup || fatal unable to start Traffic Server
-trap shutdown 0 EXIT
-
-#msg unpacking the SSL certificates into \$sysconfdir/ssl.
-#(
-#  tarball=$(cd $(dirname $0) && pwd)/ssl-multicert-bundle.tar.bz2
-#  conf=$TSQA_ROOT/$(sysconfdir)/ssl
-#
-#  cd $TSQA_ROOT/$(sysconfdir) && tar -xf $tarball
-#)
-
-msg updating SSL configuration paths
-tsexec traffic_line -s proxy.config.ssl.server.cert.path -v $TSQA_ROOT/$(sysconfdir)/ssl
-tsexec traffic_line -s proxy.config.ssl.server.multicert.filename -v $TSQA_ROOT/$(sysconfdir)/ssl/ssl_multicert.config
-
-# XXX configure an exampe plugin that uses the TS-2437 SSL lifecycle hooks
-
-# XXX hardcoding the ports is lame ...
-PORT=9443:ssl,10443:ssl,11443:ssl
-
-# Enable SSL and bounce Traffic Server.
-tsexec traffic_line -s proxy.config.diags.action.enabled -v 1
-tsexec traffic_line -s proxy.config.diags.action.tags -v test.multicert.delay
-
-tsexec traffic_line -s proxy.config.http.server_ports -v $PORT
-tsexec traffic_line -s proxy.config.diags.debug.enabled -v 1
-tsexec traffic_line -s proxy.config.diags.debug.tags -v ssl
-
-# Stash the admin port while we have traffic_server running. It won't be
-# available later if traffic_server does not come back up.
-admin_port=$(tsexec traffic_line -r proxy.config.process_manager.mgmt_port)
-
-# The sleep is needed to let Traffic Server schedule the config change.
-msgwait 2 to restart with SSL ports enabled
-tsexec traffic_line -L
-
-msgwait 6 for traffic_server to restart
-alive server || startup || fatal unable to start Traffic Server
-
-# XXX use the SSL lifecycle hooks in TS-2437 to verify that we loaded the
-# certificates.
-
-START=$(date +%s)
-
-# Verify that the healthcheck comes up within about 60 seconds.
-for c in $(seq 60) ; do
-  curl --silent --max-time 1 -o /dev/null http://127.0.0.1:${admin_port}/synthetic.txt && exit $TSQA_FAIL
-  sleep 1
-done
-
-fail unable to start traffic_server after $(( $(date +%s) - $START )) seconds
-exit $TSQA_FAIL
-
-# vim: set sw=2 ts=2 et :

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/51ea4aa9/ci/tsqa/test-privilege-elevation
----------------------------------------------------------------------
diff --git a/ci/tsqa/test-privilege-elevation b/ci/tsqa/test-privilege-elevation
deleted file mode 100755
index 2d4eda0..0000000
--- a/ci/tsqa/test-privilege-elevation
+++ /dev/null
@@ -1,83 +0,0 @@
-#! /usr/bin/env bash
-
-#  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.
-
-TSQA_TSXS=${TSQA_TSXS:-/opt/ats/bin/tsxs}
-TSQA_TESTNAME=$(basename $0)
-COUNT=${COUNT:-10}
-source $(dirname $0)/functions
-
-# This test verifies Traffic Server can elevate privileges correctly, based on
-# the configuration settings:
-#
-#       proxy.config.ssl.cert.load_elevated
-#       proxy.config.plugin.load_elevated
-
-check() {
-
-  for i in $(seq $COUNT) ; do
-    msg check $i ...
-    touch $TSQA_ROOT/$(sysconfdir)/remap.config
-    touch $TSQA_ROOT/$(sysconfdir)/ssl_multicert.config
-    tsexec traffic_line -x
-    msgwait 2
-  done
-
-  crash
-}
-
-if [ x"$(id -u)" != x"0" ] ; then
-  fatal this test needs to be run as root
-fi
-
-bootstrap
-
-# If Traffic Server is not up, bring it up ...
-alive cop || startup || fatal unable to start Traffic Server
-trap shutdown 0 EXIT
-
-tsexec traffic_line -s proxy.config.ssl.cert.load_elevated -v 1
-tsexec traffic_line -s proxy.config.plugin.load_elevated -v 1
-tsexec traffic_line -s proxy.config.diags.debug.tags -v 'privileges'
-tsexec traffic_line -s proxy.config.diags.debug.enabled -v 1
-
-cat >$TSQA_ROOT/$(sysconfdir)/remap.config <<REMAP
-# Add a remap rule, it doesn't matter what it is ..
-map http://jtest.trafficserver.apache.org http://127.0.0.1 \
-  @plugin=conf_remap.so @pparam=proxy.config.url_remap.pristine_host_hdr=1
-REMAP
-
-cat >$TSQA_ROOT/$(sysconfdir)/plugin.config <<PLUGIN
-# Add a plugin, it doesn't matter which one. A better test would load
-# a plugin that requires elevated access, and checks for it in the
-# plugin interface.
-
-xdebug.so
-PLUGIN
-
-# The sleep is needed to let Traffic Server schedule the config change.
-msgwait 4 to restart load elevation enabled
-tsexec traffic_line -L
-
-msgwait 6 for traffic_server to restart
-alive server || startup || fatal unable to start Traffic Server
-
-check
-
-exit $TSQA_FAIL
-
-# vim: set sw=2 ts=2 et :

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/51ea4aa9/ci/tsqa/test-server-intercept
----------------------------------------------------------------------
diff --git a/ci/tsqa/test-server-intercept b/ci/tsqa/test-server-intercept
deleted file mode 100755
index ee1eab3..0000000
--- a/ci/tsqa/test-server-intercept
+++ /dev/null
@@ -1,80 +0,0 @@
-#! /usr/bin/env bash
-
-#  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.
-
-TSQA_TSXS=${TSQA_TSXS:-/opt/ats/bin/tsxs}
-TSQA_TESTNAME=$(basename $0)
-source $(dirname $0)/functions
-
-# The intercept example plugin is hard-coded to port 60000.
-SERVER_PORT=${SERVER_PORT:-60000}
-
-# Use traffic_line -m to list all the configuration variables. Verify their values with
-# traffic_line -r. This tests the TSRecordGet() and TSRecordGetMatchMult() remote APIs.
-check() {
-  local key
-  local val1
-  local val2
-
-  local bindir=$(bindir)
-
-  tsexec traffic_line -m proxy.config | while read key val1 ; do
-    val2=$(TS_ROOT=$TSQA_ROOT $bindir/traffic_line -r $key)
-    if [ "$?" != "0" ]; then
-      fail failed to fetch value for $key
-    elif [ "$val1" != "$val1" ] ; then
-      fail value mismatch for $key, expected:\"$val1\", received:\"$val2\"
-    fi
-  done
-}
-
-bootstrap
-
-if [ ! -x $(bindir)/jtest ] ; then
-  fatal "missing jtest program; rebuild with --enable-test-tools"
-fi
-
-cat >$TSQA_ROOT/$(sysconfdir)/remap.config <<REMAP
-map http://jtest.trafficserver.apache.org:$SERVER_PORT http://127.0.0.1:$SERVER_PORT
-REMAP
-
-cat >$TSQA_ROOT/$(sysconfdir)/plugin.config <<REMAP
-#intercept.so
-REMAP
-
-# If Traffic Server is not up, bring it up ...
-alive cop || startup || fatal unable to start Traffic Server
-trap shutdown 0 EXIT
-
-# Wait for traffic_manager to start.
-alive manager
-alive server
-msgwait 1
-
-# Run jtest for a while to exercise the intercept path. Note that jtest only exercises
-# one of many possible sequences of events. Specifically, the jtest server will always
-# close the socket before the client finishes reasing the response.
-$(bindir)/jtest --proxy_port $PORT --proxy_host 127.0.0.1 \
-  --server_port $SERVER_PORT --server_host jtest.trafficserver.apache.org \
-  --clients 10 --test_time 60
-
-# Check for a crash ...
-crash
-
-exit $TSQA_FAIL
-
-# vim: set sw=2 ts=2 et :

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/51ea4aa9/ci/tsqa/test-ssl-certificates
----------------------------------------------------------------------
diff --git a/ci/tsqa/test-ssl-certificates b/ci/tsqa/test-ssl-certificates
deleted file mode 100755
index e12b798..0000000
--- a/ci/tsqa/test-ssl-certificates
+++ /dev/null
@@ -1,153 +0,0 @@
-#! /usr/bin/env bash
-
-#  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.
-
-TSQA_TSXS=${TSQA_TSXS:-/opt/ats/bin/tsxs}
-TSQA_TESTNAME=$(basename $0)
-source $(dirname $0)/functions
-
-OPENSSL=${OPENSSL:-openssl}
-
-check_openssl_version() {
-  local vers=$($OPENSSL version)
-
-  # Apparantly OpenSSL SNI was added in 0.9.8f, but I'm too lazy to
-  # parse the version properly, so let's just say that 1.0 and greater is ok.
-  case $vers in
-  OpenSSL\ [1-9].[0-9].*) return 0;;
-  *) return 1;;
-  esac
-}
-
-make_ssl_certificate() {
-  local cn="$1"
-  local filename="$2"
-
-  msg generating SSL key and certificate for "$cn"
-
-  $OPENSSL genrsa -out ${cn}.key 2048
-  $OPENSSL req -new -key ${cn}.key -out ${cn}.csr \
-    -subj "/C=US/ST=CA/L=Norm/O=TrafficServer/OU=Test/CN=${cn}"
-  $OPENSSL x509 -req -days 1 -in ${cn}.csr -signkey ${cn}.key -out ${cn}.crt
-
-  cat ${cn}.crt ${cn}.key > ${filename}
-
-  rm -rf ${cn}.csr ${cn}.key ${cn}.crt
-}
-
-openssl_verify_certificate() {
-  local certname="$1" # Certificate CN to expect
-  local result="$TSQA_ROOT/${certname}.result"
-  local commonName=
-  local status=1  # default status is FAIL
-
-  shift
-  msg "checking for the $certname certificate ..." | tee -a "$TSQA_ROOT/$TSQA_TESTNAME.log"
-
-  # When s_client verifies the certificate, it will log a line that looks like:
-  # depth=0 C = US, ST = CA, L = Norm, O = TrafficServer, OU = Test, CN = address.tsqa.trafficserver.apache.org
-  $OPENSSL s_client "$@" < /dev/null > "$result" 2>&1
-  if [ "$?" != 0 ]; then
-    fail "openssl check for $certname failed"
-  fi
-
-  # The output of this openssl formulation is:
-  # subject=
-  #     countryName               = US
-  #     stateOrProvinceName       = CA
-  #     localityName              = Norm
-  #     organizationName          = TrafficServer
-  #     organizationalUnitName    = Test
-  #     commonName                = *.tsqa.trafficserver.apache.org
-  commonName=$($OPENSSL x509 -in "$result" -noout -subject -nameopt multiline | awk '/commonName/{print $3}')
-
-  if [ "$commonName" != "$certname" ]; then
-    fail "received certificate CN \"$commonName\", expected \"$certname\""
-  fi
-
-  if [ "$?" != 0 ]; then
-    fail "certificate name $certname did not match"
-  fi
-}
-
-check_openssl_version || fatal OpenSSL 1.0 or later is required
-
-bootstrap
-
-# If Traffic Server is not up, bring it up ...
-alive cop || startup || fatal unable to start Traffic Server
-trap shutdown 0 EXIT
-
-for name in \
-  \*.tsqa.trafficserver.apache.org \
-  sni.tsqa.trafficserver.apache.org \
-  port.tsqa.trafficserver.apache.org \
-  address.tsqa.trafficserver.apache.org \
-  default.tsqa.trafficserver.apache.org
-do
-  logexec make_ssl_certificate $name $TSQA_ROOT/$(sysconfdir)/${name}.pem \
-    || fatal failed to generate SSL certificate for "$name"
-done
-
-cat > $TSQA_ROOT/$(sysconfdir)/ssl_multicert.config <<EOF
-ssl_cert_name=sni.tsqa.trafficserver.apache.org.pem
-ssl_cert_name=*.tsqa.trafficserver.apache.org.pem
-
-ssl_cert_name=port.tsqa.trafficserver.apache.org.pem dest_ip=127.0.0.1:10443
-ssl_cert_name=address.tsqa.trafficserver.apache.org.pem dest_ip=127.0.0.1
-ssl_cert_name=default.tsqa.trafficserver.apache.org.pem dest_ip=*
-EOF
-
-# XXX hardcoding the ports is lame ...
-PORT=9443:ssl,10443:ssl,11443:ssl
-
-# Enable SSL and bounce Traffic Server.
-tsexec traffic_line -s proxy.config.http.server_ports -v $PORT
-tsexec traffic_line -s proxy.config.diags.debug.tags -v ssl
-
-# The sleep is needed to let Traffic Server schedule the config change.
-msgwait 2 to restart with SSL ports enabled
-tsexec traffic_line -L
-
-msgwait 6 for traffic_server to restart
-alive server || startup || fatal unable to start Traffic Server
-
-# debugging ...
-# tsexec traffic_line -r proxy.config.diags.debug.tags
-# tsexec traffic_line -r proxy.config.http.server_ports
-
-# This should get *.tsqa.trafficserver.apache.org ...
-openssl_verify_certificate '*.tsqa.trafficserver.apache.org' \
-  -connect 127.0.0.1:9443 -servername wildcard.tsqa.trafficserver.apache.org
-
-# This should get sni.tsqa.trafficserver.apache.org ...
-openssl_verify_certificate 'sni.tsqa.trafficserver.apache.org' \
-  -connect 127.0.0.1:9443 -servername sni.tsqa.trafficserver.apache.org
-
-# This should get port.tsqa.trafficserver.apache.org ...
-openssl_verify_certificate 'port.tsqa.trafficserver.apache.org' \
-  -connect 127.0.0.1:10443
-
-# This should get address.tsqa.trafficserver.apache.org ...
-openssl_verify_certificate 'address.tsqa.trafficserver.apache.org' \
-  -connect 127.0.0.1:9443
-
-# XXX not sure how to get the default.tsqa.trafficserver.apache.org; need to listen on a second address for that.
-
-exit $TSQA_FAIL
-
-# vim: set sw=2 ts=2 et :

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/51ea4aa9/ci/tsqa/test-trafficline-metrics
----------------------------------------------------------------------
diff --git a/ci/tsqa/test-trafficline-metrics b/ci/tsqa/test-trafficline-metrics
deleted file mode 100755
index 1f28cbd..0000000
--- a/ci/tsqa/test-trafficline-metrics
+++ /dev/null
@@ -1,56 +0,0 @@
-#! /usr/bin/env bash
-
-#  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.
-
-TSQA_TSXS=${TSQA_TSXS:-/opt/ats/bin/tsxs}
-TSQA_TESTNAME=$(basename $0)
-source $(dirname $0)/functions
-
-# Use traffic_line -m to list all the configuration variables. Verify their values with
-# traffic_line -r. This tests the TSRecordGet() and TSRecordGetMatchMult() remote APIs.
-check() {
-  local key
-  local val1
-  local val2
-
-  local bindir=$(bindir)
-
-  tsexec traffic_line -m proxy.config | while read key val1 ; do
-    val2=$(TS_ROOT=$TSQA_ROOT $bindir/traffic_line -r $key)
-    if [ "$?" != "0" ]; then
-      fail failed to fetch value for $key
-    elif [ "$val1" != "$val1" ] ; then
-      fail value mismatch for $key, expected:\"$val1\", received:\"$val2\"
-    fi
-  done
-}
-
-bootstrap
-
-# If Traffic Server is not up, bring it up ...
-alive cop || startup || fatal unable to start Traffic Server
-trap shutdown 0 EXIT
-
-# Wait for traffic_manager to start.
-alive manager
-msgwait 1
-
-check
-
-exit $TSQA_FAIL
-
-# vim: set sw=2 ts=2 et :

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/51ea4aa9/ci/tsqa/tests/helpers.py
----------------------------------------------------------------------
diff --git a/ci/tsqa/tests/helpers.py b/ci/tsqa/tests/helpers.py
new file mode 100644
index 0000000..7333569
--- /dev/null
+++ b/ci/tsqa/tests/helpers.py
@@ -0,0 +1,57 @@
+#  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 tempfile
+
+import tsqa.environment
+import tsqa.test_cases
+import tsqa.utils
+
+unittest = tsqa.utils.import_unittest()
+
+# TODO: check that the given path is relative
+def tests_file_path(path):
+    '''
+    Return the absolute path to a file with relative path "name" from tsqa/files
+    '''
+    base = os.path.realpath(os.path.join(__file__, '..', '..', 'files'))
+    return os.path.join(base, path)
+
+class EnvironmentCase(tsqa.test_cases.EnvironmentCase):
+    '''
+    This class will get an environment (which is unique) but won't start it
+    '''
+    @classmethod
+    def getEnv(cls):
+        '''
+        This function is responsible for returning an environment
+        '''
+        SOURCE_DIR = os.path.realpath(os.path.join(__file__, '..', '..', '..', '..'))
+        TMP_DIR = os.path.join(tempfile.gettempdir(), 'tsqa')
+        ef = tsqa.environment.EnvironmentFactory(SOURCE_DIR,
+                                                 os.path.join(TMP_DIR, 'base_envs'),
+                                                 default_configure={'enable-example-plugins': None,
+                                                                    'enable-test-tools': None,
+                                                                    'disable-dependency-tracking': None,
+                                                                    'enable-ccache': None,
+                                                                    },
+                                                 )
+        # TODO: figure out a way to determine why the build didn't fail and
+        # not skip all build failures?
+        try:
+            return ef.get_environment(cls.environment_factory.get('configure'), cls.environment_factory.get('env'))
+        except Exception as e:
+            raise unittest.SkipTest(e)

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/51ea4aa9/ci/tsqa/tests/test_buildoptions.py
----------------------------------------------------------------------
diff --git a/ci/tsqa/tests/test_buildoptions.py b/ci/tsqa/tests/test_buildoptions.py
new file mode 100644
index 0000000..2279062
--- /dev/null
+++ b/ci/tsqa/tests/test_buildoptions.py
@@ -0,0 +1,61 @@
+'''
+Test that configuration options successfully compile
+'''
+
+#  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 TestBuildOption(helpers.EnvironmentCase):
+    '''
+    Run the built-in traffic_server regression test suite.
+    '''
+
+    def test_buildoption(self):
+        pass
+
+class TestBuildOptionFastSDK(TestBuildOption):
+    '''Build with --enable-fast-sdk'''
+    environment_factory = { 'configure': { 'enable-fast-sdk': None }, }
+
+class TestBuildOptionDisableDiags(TestBuildOption):
+    '''Build with --disable-diags'''
+    environment_factory = { 'configure': { 'disable-diags': None }, }
+
+class TestBuildOptionDisableTests(TestBuildOption):
+    '''Build with --disable-tests'''
+    environment_factory = { 'configure': { 'disable-tests': None }, }
+
+class TestBuildOptionEnableStaticProxy(TestBuildOption):
+    '''Build with --enable-static-proxy'''
+    environment_factory = { 'configure': { 'enable-static-proxy': None }, }
+
+class TestBuildOptionEnableCxxApi(TestBuildOption):
+    '''Build with --enable-cppapi'''
+    environment_factory = { 'configure': { 'enable-cppapi': None }, }
+

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/51ea4aa9/ci/tsqa/tests/test_chunked.py
----------------------------------------------------------------------
diff --git a/ci/tsqa/tests/test_chunked.py b/ci/tsqa/tests/test_chunked.py
new file mode 100644
index 0000000..9b7fdc0
--- /dev/null
+++ b/ci/tsqa/tests/test_chunked.py
@@ -0,0 +1,196 @@
+'''
+Test chunked request/responses
+'''
+#  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 json
+import uuid
+import socket
+
+import helpers
+
+import tsqa.test_cases
+import tsqa.utils
+import tsqa.endpoint
+
+log = logging.getLogger(__name__)
+
+import SocketServer
+class ChunkedHandler(SocketServer.BaseRequestHandler):
+    """
+    A subclass of RequestHandler which return chunked encoding optionally
+
+    /parts/sleep_time/close
+        parts: number of parts to send
+        sleep_time: time between parts
+        close: bool wether to close properly
+    """
+
+    def handle(self):
+        # Receive the data in small chunks and retransmit it
+        conn_id = uuid.uuid4().hex
+        while True:
+            data = self.request.recv(4096).strip()
+            if data:
+                log.info('sending data back to the client')
+            else:
+                log.info('Client disconnected')
+                break
+            inc_lines = data.splitlines()
+            try:
+                uri = inc_lines[0].split()[1]
+            except IndexError:
+                break
+            parts = 5  # how many things to send
+            sleep_time = 0.2  # how long to sleep between parts
+            close = True  # whether to close properly
+            if uri[1:]:  # if there is something besides /
+                uri_parts = uri[1:].split('/')
+                if len(uri_parts) >= 1:
+                    parts = int(uri_parts[0])
+                if len(uri_parts) >= 2:
+                    sleep_time = float(uri_parts[1])
+                if len(uri_parts) >= 3:
+                    close = json.loads(uri_parts[2])
+            resp = ('HTTP/1.1 200 OK\r\n'
+                    'X-Conn-Id: ' + str(conn_id) + '\r\n'
+                    'Transfer-Encoding: chunked\r\n'
+                    'Connection: keep-alive\r\n'
+                    '\r\n')
+            self.request.sendall(resp)
+            for x in xrange(0, parts):
+                self.request.sendall('{0}\r\n{1}\r\n'.format(len(str(x)), x))
+                time.sleep(sleep_time)
+            if close:
+                self.request.sendall('0\r\n\r\n')
+            else:
+                self.request.sendall('lkfjasd;lfjas;d')
+
+            time.sleep(2)
+
+class TestChunked(helpers.EnvironmentCase):
+    @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.port = tsqa.utils.bind_unused_port()[1]
+        cls.server = tsqa.endpoint.SocketServerDaemon(ChunkedHandler, port=cls.port)
+        cls.server.start()
+        cls.server.ready.wait()
+
+        cls.configs['remap.config'].add_line('map / http://127.0.0.1:{0}/'.format(cls.port))
+
+        cls.configs['records.config']['CONFIG'].update({
+            'proxy.config.http.connect_attempts_timeout': 5,
+            'proxy.config.http.connect_attempts_max_retries': 0,
+            'proxy.config.http.keep_alive_enabled_in': 1,
+            'proxy.config.http.keep_alive_enabled_out': 1,
+            'proxy.config.exec_thread.limit': 1,
+            'proxy.config.exec_thread.autoconfig': 0,
+            'proxy.config.http.chunking_enabled': 1,
+        })
+
+    def test_chunked_origin(self):
+        '''
+        Test that the origin does in fact support keepalive
+        '''
+        self._client_test_chunked_keepalive(self.port)
+        self._client_test_chunked_keepalive(self.port, num_bytes=2)
+        self._client_test_chunked_keepalive(self.port, num_bytes=2, sleep=1)
+
+    def _client_test_chunked_keepalive(self,
+                                       port=None,
+                                       times=3,
+                                       num_bytes=None,
+                                       sleep=None,
+                                       ):
+        if port is None:
+            port = int(self.configs['records.config']['CONFIG']['proxy.config.http.server_ports'])
+        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+        s.connect(('127.0.0.1', port))
+
+        url = '/'
+        if num_bytes is not None:
+            url += str(num_bytes)
+        if sleep is not None:
+            if num_bytes is None:
+                raise Exception()
+            url += '/' + str(sleep)
+
+        request = ('GET ' + url + ' HTTP/1.1\r\n'
+                   'Host: 127.0.0.1\r\n'
+                   '\r\n')
+        uuid = None
+        # test basic
+        for x in xrange(1, times):
+            s.send(request)
+            resp = ''
+            while True:
+                response = s.recv(4096)
+                for line in response.splitlines():
+                    line = line.strip()
+                    if line.startswith('X-Conn-Id:'):
+                        r_uuid = line.replace('X-Conn-Id:', '')
+                        if uuid is None:
+                            uuid = r_uuid
+                        else:
+                            self.assertEqual(uuid, r_uuid)
+                resp += response
+                if resp.endswith('\r\n0\r\n\r\n'):
+                    break
+            for x in xrange(0, num_bytes or 4):
+                self.assertIn('1\r\n{0}\r\n'.format(x), resp)
+        s.close()
+
+    def test_chunked_basic(self):
+        url = 'http://127.0.0.1:{0}'.format(self.port)
+        ret = requests.get(url, proxies=self.proxies)
+        self.assertEqual(ret.status_code, 200)
+        self.assertEqual(ret.text.strip(), '01234')
+
+    # TODO: fix keepalive with chunked responses
+    def test_chunked_keepalive_server(self):
+        url = 'http://127.0.0.1:{0}'.format(self.port)
+        ret = requests.get(url, proxies=self.proxies)
+        conn_id = ret.headers['x-conn-id']
+        self.assertEqual(ret.status_code, 200)
+        self.assertEqual(ret.text.strip(), '01234')
+
+        # make sure that a second request works, and since we have keep-alive out
+        # disabled it should be a new connection
+        ret = requests.get(url, proxies=self.proxies)
+        self.assertEqual(ret.status_code, 200)
+        self.assertEqual(ret.text.strip(), '01234')
+        self.assertEqual(conn_id, ret.headers['x-conn-id'])
+
+    def test_chunked_keepalive_client(self):
+        self._client_test_chunked_keepalive()
+        self._client_test_chunked_keepalive(num_bytes=2)
+        self._client_test_chunked_keepalive(num_bytes=2, sleep=1)
+
+    def test_chunked_bad_close(self):
+        url = 'http://127.0.0.1:{0}/5/0.1/false'.format(self.port)
+        with self.assertRaises(requests.exceptions.ConnectionError):
+            ret = requests.get(url, proxies=self.proxies, timeout=2)

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/51ea4aa9/ci/tsqa/tests/test_connect_attempts.py
----------------------------------------------------------------------
diff --git a/ci/tsqa/tests/test_connect_attempts.py b/ci/tsqa/tests/test_connect_attempts.py
new file mode 100644
index 0000000..9979e33
--- /dev/null
+++ b/ci/tsqa/tests/test_connect_attempts.py
@@ -0,0 +1,209 @@
+'''
+Test Origin Server Connect Attempts
+'''
+#  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 time
+import logging
+import socket
+import struct
+import select
+import threading
+
+import helpers
+
+import tsqa.test_cases
+import tsqa.utils
+import tsqa.endpoint
+
+log = logging.getLogger(__name__)
+
+
+def thread_die_on_connect(sock):
+    sock.listen(0)
+    # poll
+    read_sock = select.select([sock], [], [])
+    # exit
+    sock.close()
+
+def thread_delayed_accept_after_connect(sock):
+    '''
+    Thread to sleep a decreasing amount of time before requests
+
+    sleep times: 2 -> 1 -> 0
+    '''
+    sock.listen(0)
+    sleep_time = 2
+    requests = 0
+    # poll
+    while True:
+        read_sock = select.select([sock], [], [])
+        time.sleep(sleep_time)
+        try:
+            connection, addr = sock.accept()
+            connection.send(('HTTP/1.1 200 OK\r\n'
+                    'Content-Length: {body_len}\r\n'
+                    'Content-Type: text/html; charset=UTF-8\r\n'
+                    'Connection: close\r\n\r\n{body}'.format(body_len=len(str(requests)), body=requests)))
+            connection.close()
+            requests += 1
+        except Exception as e:
+            print 'connection died!', e
+            pass
+        if sleep_time > 0:
+            sleep_time -= 1
+
+
+def thread_reset_after_accept(sock):
+    sock.listen(0)
+    first = True
+    requests = 0
+    while True:
+        connection, addr = sock.accept()
+        requests += 1
+        if first:
+            first = False
+            connection.setsockopt(socket.SOL_SOCKET, socket.SO_LINGER, struct.pack('ii', 1, 0))
+            connection.close()
+        else:
+            connection.send(('HTTP/1.1 200 OK\r\n'
+                    'Content-Length: {body_len}\r\n'
+                    'Content-Type: text/html; charset=UTF-8\r\n'
+                    'Connection: close\r\n\r\n{body}'.format(body_len=len(str(requests)), body=requests)))
+            connection.close()
+
+def thread_partial_response(sock):
+    sock.listen(0)
+    first = True
+    requests = 0
+    while True:
+        connection, addr = sock.accept()
+        requests += 1
+        if first:
+            connection.send('HTTP/1.1 200 OK\r\n')
+            connection.setsockopt(socket.SOL_SOCKET, socket.SO_LINGER, struct.pack('ii', 1, 0))
+            connection.close()
+            first = False
+        else:
+            connection.send(('HTTP/1.1 200 OK\r\n'
+                    'Content-Length: {body_len}\r\n'
+                    'Content-Type: text/html; charset=UTF-8\r\n'
+                    'Connection: close\r\n\r\n{body}'.format(body_len=len(str(requests)), body=requests)))
+            connection.close()
+
+
+
+class TestOriginServerConnectAttempts(helpers.EnvironmentCase):
+    @classmethod
+    def setUpEnv(cls, env):
+        '''
+        This function is responsible for setting up the environment for this fixture
+        This includes everything pre-daemon start
+        '''
+        cls.sock_map = {}
+        def _add_sock(name):
+            sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+            sock.bind(('127.0.0.1', 0))
+            cls.sock_map[name] = sock.getsockname()[1]
+            cls.configs['remap.config'].add_line('map /{0}/ http://127.0.0.1:{1}/'.format(name, cls.sock_map[name]))
+            return sock
+        # create a socket where we just bind
+        _add_sock('bound')
+
+        # create a socket where we bind + listen
+        sock = _add_sock('listen')
+        sock.listen(1)
+
+        # create a bunch of special socket servers
+        sock = _add_sock('die_on_connect')
+        t = threading.Thread(target=thread_die_on_connect, args=(sock,))
+        t.daemon = True
+        t.start()
+
+        sock = _add_sock('reset_after_accept')
+        t = threading.Thread(target=thread_reset_after_accept, args=(sock,))
+        t.daemon = True
+        t.start()
+
+        sock = _add_sock('delayed_accept_after_connect')
+        t = threading.Thread(target=thread_delayed_accept_after_connect, args=(sock,))
+        t.daemon = True
+        t.start()
+
+        sock = _add_sock('partial_response')
+        t = threading.Thread(target=thread_partial_response, args=(sock,))
+        t.daemon = True
+        t.start()
+
+        # only add server headers when there weren't any
+        cls.configs['records.config']['CONFIG']['proxy.config.http.response_server_enabled'] = 2
+
+        # enable re-connects, timeout of 1s, max retires of 3
+        cls.configs['records.config']['CONFIG']['proxy.config.http.connect_attempts_timeout'] = 1
+        cls.configs['records.config']['CONFIG']['proxy.config.http.connect_attempts_max_retries'] = 3
+
+    def test_bound_origin(self):
+        '''Verify that we get 502s from an origin which just did a bind'''
+        url = 'http://127.0.0.1:{0}/bound/s'.format(self.configs['records.config']['CONFIG']['proxy.config.http.server_ports'])
+        ret = requests.get(url)
+        self.assertEqual(ret.status_code, 502)
+
+    def test_listen_origin(self):
+        '''Verify that we get 502s from origins that bind + listen'''
+        url = 'http://127.0.0.1:{0}/listen/s'.format(self.configs['records.config']['CONFIG']['proxy.config.http.server_ports'])
+        ret = requests.get(url)
+        self.assertEqual(ret.status_code, 502)
+
+        url = 'http://127.0.0.1:{0}/listen/s'.format(self.configs['records.config']['CONFIG']['proxy.config.http.server_ports'])
+        ret = requests.get(url)
+        self.assertEqual(ret.status_code, 502)
+
+    def test_die_on_connect_origin(self):
+        '''Verify that we get 504s from origins that die_on_connect'''
+        url = 'http://127.0.0.1:{0}/die_on_connect/s'.format(self.configs['records.config']['CONFIG']['proxy.config.http.server_ports'])
+        ret = requests.get(url)
+        self.assertEqual(ret.status_code, 504)
+
+    # TODO: FIX THIS!!! The test is correct, ATS isn't!
+    # we should fail in this case-- or at least have a config which lets you control
+    def test_partial_response_origin(self):
+        '''
+        Verify that we get 504s from origins that return a partial_response
+
+        We want to bail out-- since the origin already got the request, we can't
+        gaurantee that the request is re-entrant
+        '''
+        url = 'http://127.0.0.1:{0}/partial_response/s'.format(self.configs['records.config']['CONFIG']['proxy.config.http.server_ports'])
+        ret = requests.get(url)
+        self.assertEqual(ret.status_code, 502)
+
+    def test_reset_after_accept_origin(self):
+        '''Verify that we get 200s from origins that reset_after_accept'''
+        url = 'http://127.0.0.1:{0}/reset_after_accept/s'.format(self.configs['records.config']['CONFIG']['proxy.config.http.server_ports'])
+        ret = requests.get(url)
+        self.assertEqual(ret.status_code, 200)
+        self.assertGreater(int(ret.text), 0)
+
+    def test_delayed_accept_after_connect_origin(self):
+        '''Verify that we get 200s from origins that delayed_accept_after_connect'''
+        url = 'http://127.0.0.1:{0}/delayed_accept_after_connect/s'.format(self.configs['records.config']['CONFIG']['proxy.config.http.server_ports'])
+        ret = requests.get(url)
+        # make sure it worked
+        self.assertEqual(ret.status_code, 200)
+        # make sure its not the first one (otherwise the test messed up somehow)
+        self.assertGreater(int(ret.text), 0)

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/51ea4aa9/ci/tsqa/tests/test_example.py
----------------------------------------------------------------------
diff --git a/ci/tsqa/tests/test_example.py b/ci/tsqa/tests/test_example.py
new file mode 100644
index 0000000..0a7f468
--- /dev/null
+++ b/ci/tsqa/tests/test_example.py
@@ -0,0 +1,234 @@
+'''
+Some example tests of the new tsqa
+'''
+
+#  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 subprocess
+
+import helpers
+
+import tsqa.test_cases
+import tsqa.utils
+
+# TODO: for some reason subclasses of subclasses of TestCase don't work with the
+# decorator
+#@helpers.unittest.skip('Not running TestNoOp, as it is a NoOp test')
+class TestNoOp(helpers.EnvironmentCase):
+    '''
+    This is purely a documentation test
+    '''
+    # you can set configure/environment options for the source build here
+    environment_factory = {
+        'configure': {# A value of None means that the argument has no value
+                      'enable-spdy': None,
+                      # if there is a value it will be converted to --key=value
+                      'with-max-api-stats': 2048,
+                      },
+        'env': None,
+    }
+
+    @classmethod
+    def setUpClass(cls):
+        '''
+        If you'd like to skip an entire test
+        '''
+        # you can also skip (or conditionally skip) tests
+        raise helpers.unittest.SkipTest('Skip the entire class')
+
+    @classmethod
+    def setUpEnv(cls, env):
+        '''
+        This funciton is responsible for setting up the environment for this fixture
+        This includes everything pre-daemon start.
+
+        You are passed in cls (which is the instance of this class) and env (which
+        is an environment object)
+        '''
+        # we can modify any/all configs (note: all pre-daemon start)
+        cls.configs['remap.config'].add_line('map / http://http://trafficserver.readthedocs.org/')
+
+        # Some configs have nicer wrapper objects to give you a more pythonic interface
+        cls.configs['records.config']['CONFIG'].update({
+            'proxy.config.log.squid_log_enabled': 1,
+            'proxy.config.log.squid_log_is_ascii': 1,
+        })
+
+    def test_something(self):
+        '''
+        All functions beginning with "test_" will be run as tests for the class.
+        Within these functions your environment is already set up and started--
+        you only need to excercise the code that you intend to test
+        '''
+        # for example, you could send a request to ATS and check the response
+        ret = requests.get('http://127.0.0.1:{0}/'.format(self.configs['records.config']['CONFIG']['proxy.config.http.server_ports']))
+
+        self.assertEqual(ret.status_code, 404)
+        self.assertIn('ATS', ret.headers['server'])
+
+
+class TestConfigureFlags(helpers.EnvironmentCase):
+    environment_factory = {
+        'configure': {'enable-spdy': None},
+    }
+
+    def test_spdy(self):
+        self.assertTrue(True)
+
+
+class TestBootstrap(helpers.EnvironmentCase):
+    def test_default_404(self):
+        ret = requests.get('http://127.0.0.1:{0}/'.format(self.configs['records.config']['CONFIG']['proxy.config.http.server_ports']))
+
+        self.assertEqual(ret.status_code, 404)
+        self.assertIn('ATS', ret.headers['server'])
+
+    def test_trafficline(self):
+        '''
+        Test that traffic_line works, and verify that the values for proxy.config
+        match what we put in records.config
+        '''
+        cmd = [os.path.join(self.environment.layout.bindir, 'traffic_line'),
+               '-m',
+               'proxy.config',
+               ]
+        stdout, _ = tsqa.utils.run_sync_command(cmd, stdout=subprocess.PIPE)
+        for line in stdout.splitlines():
+            if not line.strip():
+                continue
+            k, v = line.split(' ', 1)
+            if k not in self.configs['records.config']['CONFIG']:
+                continue
+            r_val = self.configs['records.config']['CONFIG'][k]
+            self.assertEqual(type(r_val)(v), self.configs['records.config']['CONFIG'][k])
+
+
+class TestServerIntercept(helpers.EnvironmentCase, tsqa.test_cases.DynamicHTTPEndpointCase):
+    endpoint_port = 60000
+    @classmethod
+    def setUpEnv(cls, env):
+        cls.configs['remap.config'].add_line('map / http://127.0.0.1:{0}'.format(cls.endpoint_port))
+
+        cls.configs['plugin.config'].add_line('intercept.so')
+
+        def hello(request):
+            return 'hello'
+        cls.http_endpoint.add_handler('/', hello)
+
+
+    def test_basic_intercept(self):
+        for _ in xrange(0, 10):
+            ret = requests.get('http://127.0.0.1:{0}/'.format(self.configs['records.config']['CONFIG']['proxy.config.http.server_ports']))
+
+            self.assertEqual(ret.status_code, 200)
+
+
+class TestLogs(helpers.EnvironmentCase):
+    @classmethod
+    def setUpEnv(cls, env):
+        '''
+        This funciton is responsible for setting up the environment for this fixture
+        This includes everything pre-daemon start
+        '''
+        # only add server headers when there weren't any
+        cls.configs['records.config']['CONFIG'].update({
+            'proxy.config.diags.debug.tags': 'log-.*',
+            'proxy.config.diags.debug.enabled': 1,
+            'proxy.config.log.hostname': 'test',
+            'proxy.config.log.search_top_sites': 1,
+        })
+    def test_logs_exist(self):
+        # send some requests
+        for x in xrange(0, 10):
+            ret = requests.get('http://127.0.0.1:{0}/'.format(self.configs['records.config']['CONFIG']['proxy.config.http.server_ports']))
+
+            self.assertEqual(ret.status_code, 404)
+            self.assertIn('ATS', ret.headers['server'])
+
+        # TODO: some better way to know when the logs where syncd
+        time.sleep(10)  # wait for logs to hit disk
+
+        # verify that the log files exist
+        for logfile in ('diags.log', 'error.log', 'squid.blog', 'traffic.out', 'manager.log'):
+            logfile_path = os.path.join(self.environment.layout.logdir, logfile)
+            self.assertTrue(os.path.isfile(logfile_path), logfile_path)
+
+
+class TestLogRefCounting(tsqa.test_cases.DynamicHTTPEndpointCase, helpers.EnvironmentCase):
+    @classmethod
+    def setUpEnv(cls, env):
+        '''
+        This funciton is responsible for setting up the environment for this fixture
+        This includes everything pre-daemon start
+        '''
+        cls.configs['remap.config'].add_line('map / http://127.0.0.1:{0}/\n'.format(cls.http_endpoint.address[1]))
+
+        cls.configs['plugin.config'].add_lines([
+            'tcpinfo.so --log-file=tcpinfo1 --hooks=ssn_start,txn_start,send_resp_hdr,ssn_close,txn_close --log-level=2',
+            'tcpinfo.so --log-file=tcpinfo2 --hooks=ssn_start,txn_start,send_resp_hdr,ssn_close,txn_close --log-level=2',
+            'tcpinfo.so --log-file=tcpinfo3 --hooks=ssn_start,txn_start,send_resp_hdr,ssn_close,txn_close --log-level=2',
+            'tcpinfo.so --log-file=tcpinfo4 --hooks=ssn_start,txn_start,send_resp_hdr,ssn_close,txn_close --log-level=2',
+        ])
+
+        # only add server headers when there weren't any
+        cls.configs['records.config']['CONFIG'].update({
+            'proxy.config.log.max_space_mb_for_logs': 10,
+            'proxy.config.log.max_space_mb_for_orphan_logs': 10,
+            'proxy.config.log.squid_log_enabled': 1,
+            'proxy.config.log.squid_log_is_ascii': 1,
+            'proxy.config.log.rolling_interval_sec': 60,
+            'proxy.config.log.rolling_size_mb': 1,
+            'proxy.config.log.max_space_mb_headroom': 1,
+            'proxy.config.log.max_secs_per_buffer': 1,
+        })
+
+    def test_logs_exist(self):
+        # send some requests
+        for x in xrange(0, 10):
+            ret = requests.get('http://127.0.0.1:{0}/'.format(self.configs['records.config']['CONFIG']['proxy.config.http.server_ports']))
+
+            self.assertEqual(ret.status_code, 404)
+            self.assertIn('ATS', ret.headers['server'])
+
+        # TODO: some better way to know when the logs where syncd
+        time.sleep(10)  # wait for logs to hit disk
+
+        logfile_path = os.path.join(self.environment.layout.logdir, 'squid.log')
+        self.assertTrue(os.path.isfile(logfile_path), logfile_path)
+
+
+class TestDynamicHTTPEndpointCase(tsqa.test_cases.DynamicHTTPEndpointCase, helpers.EnvironmentCase):
+    @classmethod
+    def setUpEnv(cls, env):
+        '''
+        This funciton is responsible for setting up the environment for this fixture
+        This includes everything pre-daemon start
+        '''
+        cls.configs['remap.config'].add_line('map / http://127.0.0.1:{0}/\n'.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
+
+    def test_basic_proxy(self):
+        ret = requests.get(self.endpoint_url('/test'),
+                           proxies=self.proxies,
+                           )
+        self.assertEqual(ret.status_code, 404)
+        self.assertIn('WSGIServer', ret.headers['server'])

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/51ea4aa9/ci/tsqa/tests/test_hostdb.py
----------------------------------------------------------------------
diff --git a/ci/tsqa/tests/test_hostdb.py b/ci/tsqa/tests/test_hostdb.py
new file mode 100644
index 0000000..46bec6a
--- /dev/null
+++ b/ci/tsqa/tests/test_hostdb.py
@@ -0,0 +1,86 @@
+'''
+Test hostdb
+'''
+
+#  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 helpers
+
+import tsqa.test_cases
+
+
+class TestHostDBPartiallyFailedDNS(helpers.EnvironmentCase):
+    '''
+    Tests for how hostdb handles when there is one failed and one working resolver
+    '''
+    @classmethod
+    def setUpEnv(cls, env):
+        resolv_conf_path = os.path.join(env.layout.prefix, 'resolv.conf')
+
+        cls.configs['records.config']['CONFIG'].update({
+            'proxy.config.http.response_server_enabled': 2,  # only add server headers when there weren't any
+            'proxy.config.hostdb.lookup_timeout': 1,
+            'proxy.config.dns.resolv_conf': resolv_conf_path,
+            'proxy.config.url_remap.remap_required': 0,
+
+        })
+
+        with open(resolv_conf_path, 'w') as fh:
+            fh.write('nameserver 1.1.1.0\n')  # some non-existant nameserver
+            fh.write('nameserver 8.8.8.8\n')  # some REAL nameserver
+
+    def test_working(self):
+        start = time.time()
+        ret = requests.get('http://trafficserver.readthedocs.org',
+                           proxies=self.proxies,
+                           )
+        self.assertLess(time.time() - start, self.configs['records.config']['CONFIG']['proxy.config.hostdb.lookup_timeout'])
+        self.assertEqual(ret.status_code, 200)
+
+
+class TestHostDBFailedDNS(helpers.EnvironmentCase):
+    '''
+    Tests for how hostdb handles when there is no reachable resolver
+    '''
+    @classmethod
+    def setUpEnv(cls, env):
+        resolv_conf_path = os.path.join(env.layout.prefix, 'resolv.conf')
+
+        cls.configs['records.config']['CONFIG'].update({
+            'proxy.config.http.response_server_enabled': 2,  # only add server headers when there weren't any
+            'proxy.config.hostdb.lookup_timeout': 1,
+            'proxy.config.dns.resolv_conf': resolv_conf_path,
+            'proxy.config.url_remap.remap_required': 0,
+
+        })
+
+        with open(resolv_conf_path, 'w') as fh:
+            fh.write('nameserver 1.1.1.0\n')  # some non-existant nameserver
+
+    def test_lookup_timeout(self):
+        start = time.time()
+        ret = requests.get('http://some_nonexistant_domain',
+                           proxies=self.proxies,
+                           )
+        self.assertGreater(time.time() - start, self.configs['records.config']['CONFIG']['proxy.config.hostdb.lookup_timeout'])
+        self.assertEqual(ret.status_code, 502)
+        self.assertIn('ATS', ret.headers['server'])
+

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/51ea4aa9/ci/tsqa/tests/test_https.py
----------------------------------------------------------------------
diff --git a/ci/tsqa/tests/test_https.py b/ci/tsqa/tests/test_https.py
new file mode 100644
index 0000000..a8914e6
--- /dev/null
+++ b/ci/tsqa/tests/test_https.py
@@ -0,0 +1,273 @@
+#  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 logging
+from OpenSSL import SSL
+import socket
+
+import helpers
+import tsqa.utils
+
+# some ciphers to test with
+CIPHER_MAP = {
+    'rsa': 'ECDHE-RSA-AES256-GCM-SHA384',
+    'ecdsa': 'ECDHE-ECDSA-AES256-GCM-SHA384',
+}
+
+
+class CertSelectionMixin(object):
+    def _get_cert(self, addr, sni_name=None, ciphers=None):
+        '''
+        Return the certificate for addr. Optionally sending sni_name
+        '''
+        ctx = SSL.Context(SSL.TLSv1_2_METHOD)
+        # Set up client
+        sock = SSL.Connection(ctx, socket.socket(socket.AF_INET, socket.SOCK_STREAM))
+        sock.connect(addr)
+        if sni_name is not None:
+            sock.set_tlsext_host_name(sni_name)
+        if ciphers is not None:
+            ctx.set_cipher_list(ciphers)
+        sock.do_handshake()
+        return sock.get_peer_certificate()
+
+    def _get_cert_chain(self, addr, sni_name=None, ciphers=None):
+        '''
+        Return the certificate chain for addr. Optionally sending sni_name
+        '''
+        ctx = SSL.Context(SSL.TLSv1_2_METHOD)
+        # Set up client
+        sock = SSL.Connection(ctx, socket.socket(socket.AF_INET, socket.SOCK_STREAM))
+        sock.connect(addr)
+        if sni_name is not None:
+            sock.set_tlsext_host_name(sni_name)
+        if ciphers is not None:
+            ctx.set_cipher_list(ciphers)
+        sock.do_handshake()
+        return sock.get_peer_cert_chain()
+
+    def test_star_ordering(self):
+        '''
+        We should be served the first match, since we aren't sending SNI headers
+        '''
+        addr = ('127.0.0.1', self.ssl_port)
+        cert = self._get_cert(addr)
+        self.assertEqual(cert.get_subject().commonName.decode(), 'www.example.com')
+
+    def test_star_sni(self):
+        '''
+        Make sure we get the certificate we asked for if we pass in SNI headers
+        '''
+        addr = ('127.0.0.1', self.ssl_port)
+        cert = self._get_cert(addr, sni_name='www.test.com')
+        self.assertEqual(cert.get_subject().commonName.decode(), 'www.test.com')
+
+        cert = self._get_cert(addr, sni_name='www.example.com')
+        self.assertEqual(cert.get_subject().commonName.decode(), 'www.example.com')
+
+    def test_ip_ordering(self):
+        '''
+        We should be served the first match, since we aren't sending SNI headers
+        '''
+        addr = ('127.0.0.2', self.ssl_port)
+        cert = self._get_cert(addr)
+        self.assertEqual(cert.get_subject().commonName.decode(), 'www.example.com')
+
+    def test_ip_sni(self):
+        '''
+        Make sure we get the certificate we asked for if we pass in SNI headers
+        '''
+        addr = ('127.0.0.2', self.ssl_port)
+        cert = self._get_cert(addr, sni_name='www.test.com')
+        self.assertEqual(cert.get_subject().commonName.decode(), 'www.test.com')
+
+        cert = self._get_cert(addr, sni_name='www.example.com')
+        self.assertEqual(cert.get_subject().commonName.decode(), 'www.example.com')
+
+    def _intermediate_ca_t(self, cipher):
+        '''
+        Method for testing intermediate CAs. We assume that www.example.com should
+        return a certificate chaing of len 2 which includes intermediate.
+        We also assume that www.test.com returns a single cert in the chain which
+        is *not* intermediate
+        '''
+        # send a request that *should* get an intermediate CA
+        addr = ('127.0.0.1', self.ssl_port)
+        cert_chain = self._get_cert_chain(addr, ciphers=CIPHER_MAP[cipher])
+        self.assertEqual(len(cert_chain), 2)
+        self.assertEqual(cert_chain[0].get_subject().commonName.decode(), 'www.example.com')
+        self.assertEqual(cert_chain[1].get_subject().commonName.decode(), 'intermediate')
+
+        # send a request that shouldn't get an intermediate CA
+        addr = ('127.0.0.1', self.ssl_port)
+        cert_chain = self._get_cert_chain(addr, ciphers=CIPHER_MAP[cipher], sni_name='www.test.com')
+        self.assertEqual(len(cert_chain), 1)
+        self.assertEqual(cert_chain[0].get_subject().commonName.decode(), 'www.test.com')
+
+
+class TestRSA(helpers.EnvironmentCase, CertSelectionMixin):
+    '''
+    Tests for https for ATS configured with RSA certificates
+    '''
+    @classmethod
+    def setUpEnv(cls, env):
+        # add 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': 'ssl',
+            'proxy.config.ssl.server.cipher_suite': CIPHER_MAP['rsa'],
+        })
+
+        # configure SSL multicert
+        cls.configs['ssl_multicert.config'].add_line('dest_ip=127.0.0.2 ssl_cert_name={0} ssl_ca_name={1}'.format(
+            helpers.tests_file_path('rsa_keys/www.example.com.pem'),
+            helpers.tests_file_path('rsa_keys/intermediate.crt'),
+            ))
+        cls.configs['ssl_multicert.config'].add_line('dest_ip=127.0.0.2 ssl_cert_name={0}'.format(
+            helpers.tests_file_path('rsa_keys/www.test.com.pem'),
+            ))
+
+        cls.configs['ssl_multicert.config'].add_line('dest_ip=* ssl_cert_name={0} ssl_ca_name={1}'.format(
+            helpers.tests_file_path('rsa_keys/www.example.com.pem'),
+            helpers.tests_file_path('rsa_keys/intermediate.crt'),
+            ))
+        cls.configs['ssl_multicert.config'].add_line('dest_ip=* ssl_cert_name={0}'.format(
+            helpers.tests_file_path('rsa_keys/www.test.com.pem'),
+            ))
+
+    def test_rsa(self):
+        addr = ('127.0.0.1', self.ssl_port)
+        cert = self._get_cert(addr, ciphers=CIPHER_MAP['rsa'])
+        self.assertEqual(cert.get_subject().commonName.decode(), 'www.example.com')
+
+    def test_ecdsa(self):
+        addr = ('127.0.0.1', self.ssl_port)
+        with self.assertRaises(Exception):
+            cert = self._get_cert(addr, ciphers=CIPHER_MAP['ecdsa'])
+            self.assertEqual(cert.get_subject().commonName.decode(), 'www.example.com')
+
+    def test_intermediate_ca_rsa(self):
+        self._intermediate_ca_t('rsa')
+
+    def test_intermediate_ca_ecdsa(self):
+        with self.assertRaises(Exception):
+            self._intermediate_ca_t('ecdsa')
+
+class TestECDSA(helpers.EnvironmentCase, CertSelectionMixin):
+    '''
+    Tests for https for ATS configured with ECDSA certificates
+    '''
+    @classmethod
+    def setUpEnv(cls, env):
+        # add 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': 'ssl',
+            'proxy.config.ssl.server.cipher_suite': CIPHER_MAP['ecdsa'],
+        })
+
+        # configure SSL multicert
+        cls.configs['ssl_multicert.config'].add_line('dest_ip=127.0.0.2 ssl_cert_name={0} ssl_ca_name={1}'.format(
+            helpers.tests_file_path('ec_keys/www.example.com.pem'),
+            helpers.tests_file_path('ec_keys/intermediate.crt'),
+            ))
+        cls.configs['ssl_multicert.config'].add_line('dest_ip=127.0.0.2 ssl_cert_name={0}'.format(
+            helpers.tests_file_path('ec_keys/www.test.com.pem'),
+            ))
+
+        cls.configs['ssl_multicert.config'].add_line('dest_ip=* ssl_cert_name={0} ssl_ca_name={1}'.format(
+            helpers.tests_file_path('ec_keys/www.example.com.pem'),
+            helpers.tests_file_path('ec_keys/intermediate.crt'),
+            ))
+        cls.configs['ssl_multicert.config'].add_line('dest_ip=* ssl_cert_name={0}'.format(
+            helpers.tests_file_path('ec_keys/www.test.com.pem'),
+            ))
+
+    def test_rsa(self):
+        addr = ('127.0.0.1', self.ssl_port)
+        with self.assertRaises(Exception):
+            cert = self._get_cert(addr, ciphers=CIPHER_MAP['rsa'])
+            self.assertEqual(cert.get_subject().commonName.decode(), 'www.example.com')
+
+    def test_ecdsa(self):
+        addr = ('127.0.0.1', self.ssl_port)
+        cert = self._get_cert(addr, ciphers=CIPHER_MAP['ecdsa'])
+        self.assertEqual(cert.get_subject().commonName.decode(), 'www.example.com')
+
+    def test_intermediate_ca_rsa(self):
+        with self.assertRaises(Exception):
+            self._intermediate_ca_t('rsa')
+
+    def test_intermediate_ca_ecdsa(self):
+        self._intermediate_ca_t('ecdsa')
+
+class TestMix(helpers.EnvironmentCase, CertSelectionMixin):
+    '''
+    Tests for https for ATS configured with both ECDSA and RSA certificates
+    '''
+    @classmethod
+    def setUpEnv(cls, env):
+        # add 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': 'ssl',
+            'proxy.config.ssl.server.cipher_suite': '{0}:{1}'.format(CIPHER_MAP['ecdsa'], CIPHER_MAP['rsa']),
+        })
+
+        # configure SSL multicert
+        cls.configs['ssl_multicert.config'].add_line('dest_ip=127.0.0.2 ssl_cert_name={0},{1} ssl_ca_name={2},{3}'.format(
+            helpers.tests_file_path('rsa_keys/www.example.com.pem'),
+            helpers.tests_file_path('ec_keys/www.example.com.pem'),
+            helpers.tests_file_path('rsa_keys/intermediate.crt'),
+            helpers.tests_file_path('ec_keys/intermediate.crt'),
+            ))
+        cls.configs['ssl_multicert.config'].add_line('dest_ip=127.0.0.2 ssl_cert_name={0},{1}'.format(
+            helpers.tests_file_path('rsa_keys/www.test.com.pem'),
+            helpers.tests_file_path('ec_keys/www.test.com.pem'),
+            ))
+
+        cls.configs['ssl_multicert.config'].add_line('dest_ip=* ssl_cert_name={0},{1} ssl_ca_name={2},{3}'.format(
+            helpers.tests_file_path('rsa_keys/www.example.com.pem'),
+            helpers.tests_file_path('ec_keys/www.example.com.pem'),
+            helpers.tests_file_path('rsa_keys/intermediate.crt'),
+            helpers.tests_file_path('ec_keys/intermediate.crt'),
+            ))
+        cls.configs['ssl_multicert.config'].add_line('dest_ip=* ssl_cert_name={0},{1}'.format(
+            helpers.tests_file_path('rsa_keys/www.test.com.pem'),
+            helpers.tests_file_path('ec_keys/www.test.com.pem'),
+            ))
+
+    def test_rsa(self):
+        addr = ('127.0.0.1', self.ssl_port)
+        cert = self._get_cert(addr, ciphers=CIPHER_MAP['rsa'])
+        self.assertEqual(cert.get_subject().commonName.decode(), 'www.example.com')
+
+    def test_ecdsa(self):
+        addr = ('127.0.0.1', self.ssl_port)
+        cert = self._get_cert(addr, ciphers=CIPHER_MAP['ecdsa'])
+        self.assertEqual(cert.get_subject().commonName.decode(), 'www.example.com')
+
+    def test_intermediate_ca_rsa(self):
+        self._intermediate_ca_t('rsa')
+
+    def test_intermediate_ca_ecdsa(self):
+        self._intermediate_ca_t('ecdsa')