You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@trafficserver.apache.org by zw...@apache.org on 2018/01/12 16:03:50 UTC

[trafficserver] 09/09: Manual update to APIs that changed

This is an automated email from the ASF dual-hosted git repository.

zwoop pushed a commit to branch 7.1.x
in repository https://gitbox.apache.org/repos/asf/trafficserver.git

commit 2d1159ea6d10392ae8fc3a6d2a713a7521694138
Author: Jason Kenny <dr...@live.com>
AuthorDate: Tue Jan 9 17:09:38 2018 -0600

    Manual update to APIs that changed
    
    Cherry picks broke the code. Fixes to stuff that did not merge correctly or are part of other cherry picks that bring in other code we don't want in 7.1
    manual fixes and addition to test extensions to allow tests to work
    manual updates traffic_top
---
 .gitignore                                         |   4 +
 cmd/traffic_top/traffic_top.cc                     |  22 +--
 lib/records/RecCore.cc                             |   2 +-
 lib/ts/Ptr.h                                       |   2 -
 lib/ts/ink_args.cc                                 |   1 +
 mgmt/ProcessManager.cc                             |   3 +-
 tests/gold_tests/autest-site/build.test.ext        |  53 ++++++++
 tests/gold_tests/autest-site/conditions.test.ext   |  65 +++++++++
 .../autest-site/{init.cli.ext => httpbin.test.ext} |  34 ++++-
 tests/gold_tests/autest-site/init.cli.ext          |  15 ++-
 tests/gold_tests/autest-site/microserver.test.ext  | 150 ++++++++++++++-------
 tests/gold_tests/autest-site/ports.py              |  21 ++-
 tests/gold_tests/autest-site/setup.cli.ext         |  53 ++++++--
 .../gold_tests/autest-site/trafficserver.test.ext  |   6 +-
 .../autest-site/trafficserver_plugins.test.ext     |  13 +-
 tests/tools/microServer/uWServer.py                | 100 ++++++++++----
 16 files changed, 418 insertions(+), 126 deletions(-)

diff --git a/.gitignore b/.gitignore
index d9bd7bd..f3b6201 100644
--- a/.gitignore
+++ b/.gitignore
@@ -164,3 +164,7 @@ tools/trafficserver.pc
 BUILDS
 DEBUG
 RELEASE
+
+# autest
+tests/env-test/
+tests/_sandbox/
diff --git a/cmd/traffic_top/traffic_top.cc b/cmd/traffic_top/traffic_top.cc
index e217cee..99996ff 100644
--- a/cmd/traffic_top/traffic_top.cc
+++ b/cmd/traffic_top/traffic_top.cc
@@ -54,6 +54,7 @@
 #include "stats.h"
 
 #include "ts/I_Layout.h"
+#include "ts/ink_args.h"
 #include "I_RecProcess.h"
 #include "RecordsConfig.h"
 
@@ -424,29 +425,16 @@ main(int argc, const char **argv)
     break;
   }
 
-  Layout::create();
-  RecProcessInit(RECM_STAND_ALONE, nullptr /* diags */);
-  LibRecordsConfigInit();
-
-  string url = "";
+  case 1:
 #if HAS_CURL
     url = file_arguments[0];
 #else
     usage(argument_descriptions, countof(argument_descriptions), USAGE);
 #endif
+    break;
 
-    ats_scoped_str rundir(RecConfigReadRuntimeDir());
-
-    if (TS_ERR_OKAY != TSInit(rundir, static_cast<TSInitOptionT>(TS_MGMT_OPT_NO_EVENTS | TS_MGMT_OPT_NO_SOCK_TESTS))) {
-#if HAS_CURL
-      fprintf(stderr, "Error: missing URL on command line or error connecting to the local manager\n");
-#else
-      fprintf(stderr, "Error: error connecting to the local manager\n");
-#endif
-      usage();
-    }
-  } else {
-    url = argv[optind];
+  default:
+    usage(argument_descriptions, countof(argument_descriptions), USAGE);
   }
 
   Stats stats(url);
diff --git a/lib/records/RecCore.cc b/lib/records/RecCore.cc
index 0d5cea2..4fa9593 100644
--- a/lib/records/RecCore.cc
+++ b/lib/records/RecCore.cc
@@ -212,7 +212,7 @@ RecCoreInit(RecModeT mode_type, Diags *_diags)
   if ((mode_type == RECM_SERVER) || (mode_type == RECM_STAND_ALONE)) {
     bool file_exists = true;
 
-    ink_mutex_init(&g_rec_config_lock);
+    ink_mutex_init(&g_rec_config_lock, "");
 
     g_rec_config_fpath = ats_stringdup(RecConfigReadConfigPath(nullptr, REC_CONFIG_FILE REC_SHADOW_EXT));
     if (RecFileExists(g_rec_config_fpath) == REC_ERR_FAIL) {
diff --git a/lib/ts/Ptr.h b/lib/ts/Ptr.h
index fdae759..d3ac27a 100644
--- a/lib/ts/Ptr.h
+++ b/lib/ts/Ptr.h
@@ -111,10 +111,8 @@ public:
 
   T *operator->() const { return (m_ptr); }
   T &operator*() const { return (*m_ptr); }
-
   // Making this explicit avoids unwanted conversions.  See https://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Safe_bool .
   explicit operator bool() const { return m_ptr != nullptr; }
-
   int
   operator==(const T *p)
   {
diff --git a/lib/ts/ink_args.cc b/lib/ts/ink_args.cc
index bd973e3..37b4be3 100644
--- a/lib/ts/ink_args.cc
+++ b/lib/ts/ink_args.cc
@@ -229,6 +229,7 @@ process_args_ex(const AppVersionInfo *appinfo, const ArgumentDescription *argume
           }
           break;
         }
+      }
       if (i >= n_argument_descriptions) {
         return false;
       }
diff --git a/mgmt/ProcessManager.cc b/mgmt/ProcessManager.cc
index 3addf5b..b0c9be0 100644
--- a/mgmt/ProcessManager.cc
+++ b/mgmt/ProcessManager.cc
@@ -206,7 +206,8 @@ ProcessManager::initLMConnection()
   }
 
   if ((connect(local_manager_sockfd, (struct sockaddr *)&serv_addr, servlen)) < 0) {
-    mgmt_fatal(errno, "[ProcessManager::initLMConnection] failed to connect management socket '%s'\n", (const char *)sockpath);
+    mgmt_fatal(errno, "[ProcessManager::initLMConnection] failed to connect management socket '%s'\n",
+               (const char *)sockpath.c_str());
   }
 
   data_len          = sizeof(pid_t);
diff --git a/tests/gold_tests/autest-site/build.test.ext b/tests/gold_tests/autest-site/build.test.ext
new file mode 100644
index 0000000..ef8aa42
--- /dev/null
+++ b/tests/gold_tests/autest-site/build.test.ext
@@ -0,0 +1,53 @@
+'''
+Build random code for running as part of a test
+'''
+#  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 re
+import autest.common.is_a as is_a
+
+
+def Build(Test, target, sources, CPPFLAGS='', LDFLAGS='', LIBS='', CC=None):
+    if is_a.OrderedSequence(sources):
+        sources = " ".join(sources)
+    tr = Test.AddTestRun("Build", "Build test files: {0}".format(sources))
+    vars = Test.ComposeVariables()
+    if CC is None:
+        cc = vars.CXX
+    else:
+        cc = CC
+
+    tr.Processes.Default.Command = '{cc} -o {target} {cppflags} {sources} {ldflags} {libs}'.format(
+        cppflags="{0} {1}".format(vars.CPPFLAGS, CPPFLAGS),
+        ldflags="{0} {1}".format(vars.LDFLAGS, LDFLAGS),
+        libs="{0} {1}".format(vars.LIBS, LIBS),
+        target=target,
+        sources=sources,
+        cc=cc
+    )
+    tr.Processes.Default.ForceUseShell = True
+    tr.ReturnCode = 0
+    tr.Streams.All = Testers.ExcludesExpression(
+        r'(\A|\s)error?\s?(([?!: ])|(\.\s))\D',
+        "Build should not contain errors",
+        reflags=re.IGNORECASE
+    )
+
+    return tr
+
+
+ExtendTest(Build, name="Build")
diff --git a/tests/gold_tests/autest-site/conditions.test.ext b/tests/gold_tests/autest-site/conditions.test.ext
new file mode 100644
index 0000000..9cac02f
--- /dev/null
+++ b/tests/gold_tests/autest-site/conditions.test.ext
@@ -0,0 +1,65 @@
+'''
+'''
+#  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.
+
+def HasOpenSSLVersion(self, version):
+    return self.EnsureVersion(["openssl","version"],min_version=version)
+
+def HasCurlFeature(self, feature):
+
+    def default(output):
+        FEATURE_TAG = 'Features:'
+        tag = feature.lower()
+        for line in output.splitlines():
+            # look for line with starting with the Features
+            if line.startswith(FEATURE_TAG):
+                # get a features and lower case then for safety
+                line = line[len(FEATURE_TAG):].lower()
+                tokens = line.split()
+                for t in tokens:
+                    if t == tag:
+                        return True
+        return False
+
+    return self.CheckOutput(
+        ['curl', '--version'],
+        default,
+        "Curl needs to support feature: {feature}".format(feature=feature)
+    )
+
+
+def HasATSFeature(self, feature):
+
+    val = self.Variables.get(feature, None)
+
+    return self.Condition(
+        lambda: val == True,
+        "ATS feature not enabled: {feature}".format(feature=feature)
+    )
+
+#test if a plugin exists in the libexec folder
+def PluginExists(self, pluginname):
+
+    path = os.path.join(self.Variables.PLUGINDIR, pluginname)
+    return self.Condition(lambda: os.path.isfile(path) == True, path + " not found." )
+
+
+ExtendCondition(HasOpenSSLVersion)
+ExtendCondition(HasATSFeature)
+ExtendCondition(HasCurlFeature)
+ExtendCondition(PluginExists)
+
diff --git a/tests/gold_tests/autest-site/init.cli.ext b/tests/gold_tests/autest-site/httpbin.test.ext
similarity index 50%
copy from tests/gold_tests/autest-site/init.cli.ext
copy to tests/gold_tests/autest-site/httpbin.test.ext
index cc3a1a6..6e2dd86 100644
--- a/tests/gold_tests/autest-site/init.cli.ext
+++ b/tests/gold_tests/autest-site/httpbin.test.ext
@@ -16,12 +16,32 @@
 #  See the License for the specific language governing permissions and
 #  limitations under the License.
 
-import os
+from ports import get_port
 
-import sys
-if sys.version_info<(3,5,0):
-  host.WriteError("You need python 3.5 or later to run these tests\n",show_stack=False)
 
-Settings.path_argument(["--ats-bin"],
-                        required=True,
-                        help="A user provided directory to ATS bin")
\ No newline at end of file
+def MakeHttpBinServer(obj, name, port=False, ip=False, delay=False, public_ip=False, ssl=False, options={}):
+    data_dir = os.path.join(obj.RunDirectory, name)
+    # create Process
+    p = obj.Processes.Process(name)
+    if (port == False):
+        port = get_port(p, "Port")
+    if (ip == False):
+        ip = '127.0.0.1'
+    if (delay == False):
+        delay = 0
+
+    command = "gunicorn -b {0}:{1} httpbin:app".format(ip, port)
+    for flag, value in options.items():
+        command += " {} {}".format(flag, value)
+
+    # create process
+    p.Command = command
+    p.Setup.MakeDir(data_dir)
+    p.Variables.DataDir = data_dir
+    p.Ready = When.PortOpen(port, ip)
+    p.ReturnCode = Any(None, 0)
+
+    return p
+
+
+ExtendTest(MakeHttpBinServer, name="MakeHttpBinServer")
diff --git a/tests/gold_tests/autest-site/init.cli.ext b/tests/gold_tests/autest-site/init.cli.ext
index cc3a1a6..903f12f 100644
--- a/tests/gold_tests/autest-site/init.cli.ext
+++ b/tests/gold_tests/autest-site/init.cli.ext
@@ -19,9 +19,16 @@
 import os
 
 import sys
-if sys.version_info<(3,5,0):
-  host.WriteError("You need python 3.5 or later to run these tests\n",show_stack=False)
+if sys.version_info < (3, 5, 0):
+    host.WriteError(
+        "You need python 3.5 or later to run these tests\n", show_stack=False)
+
+autest_version ="1.4.2"
+if AuTestVersion() < autest_version:
+    host.WriteError(
+        "Tests need AuTest version {ver} or better\n Please update AuTest:\n  pip install --upgrade autest\n".format(ver=autest_version), show_stack=False)
+
 
 Settings.path_argument(["--ats-bin"],
-                        required=True,
-                        help="A user provided directory to ATS bin")
\ No newline at end of file
+                       required=True,
+                       help="A user provided directory to ATS bin")
diff --git a/tests/gold_tests/autest-site/microserver.test.ext b/tests/gold_tests/autest-site/microserver.test.ext
index 4c39843..4ab6783 100644
--- a/tests/gold_tests/autest-site/microserver.test.ext
+++ b/tests/gold_tests/autest-site/microserver.test.ext
@@ -19,103 +19,157 @@
 from ports import get_port
 import json
 
-def addMethod(self,testName, request_header, functionName):
+
+def addMethod(self, testName, request_header, functionName):
     return
 
 # creates the full request or response block using headers and message data
-def httpObject(self,header,data):
-    r=dict()
-    r["timestamp"]=""
-    r["headers"]=header
-    r["body"]=data
+
+
+def httpObject(self, header, data):
+    r = dict()
+    r["timestamp"] = ""
+    r["headers"] = header
+    r["body"] = data
     return r
 
 # addResponse adds customized response with respect to request_header. request_header and response_header are both dictionaries
-def addResponse(self,filename, testName, request_header, response_header):
+
+
+def addResponse(self, filename, testName, request_header, response_header):
 
     txn = dict()
     txn["timestamp"] = ""
     txn["uuid"] = testName
     txn["request"] = request_header
     txn["response"] = response_header
-    print("data dir",self.Variables.DataDir)
-    addTransactionToSession(txn,filename)
-    absFilepath=os.path.abspath(filename)
-    self.Setup.CopyAs(absFilepath,self.Variables.DataDir)
-    return
 
+    addTransactionToSession(txn, filename)
+    absFilepath = os.path.abspath(filename)
+    self.Setup.CopyAs(absFilepath, self.Variables.DataDir)
+    return
 
+def getHeaderFieldVal(request_header, field):
+    requestline = request_header["headers"].split("\r\n")[0]
+    requestline = requestline.split(" ")[1]
+    field = field+':'
+    valField = request_header["headers"].split(field,1);
+    val=""
+    if len(valField)>1:
+            field_v = valField[1].split("\r\n",1)
+            if len(field_v)>0:
+                val = field_v[0].strip()
+    return val
 
 # addResponse adds customized response with respect to request_header. request_header and response_header are both dictionaries
-def addResponse(self,filename, request_header, response_header):
+def addResponse(self, filename, request_header, response_header):
     requestline = request_header["headers"].split("\r\n")[0]
-    requestline = requestline.split(" ")[1]
-    resourceLocation = requestline.split("/",1)
-    if len(resourceLocation)>1:
-        rl = resourceLocation[1]
-    else:
-        rl = ""
+    host_ = ""
+    path_ = ""
+    if requestline:
+        url_part = requestline.split(" ")
+        if len(url_part)>1:
+            if url_part[1].startswith("http"):
+                path_ = url_part[1].split("/",2)[2]
+                host_,path_ = path_.split("/",1)
+            else:
+                path_ = url_part[1].split("/",1)[1]
+
+    kpath = ""
+    #print("Format of lookup key",self.Variables.lookup_key)
+    
+    argsList = []
+    keyslist = self.Variables.lookup_key.split("}")
+    for keystr in keyslist:
+        if keystr == '{PATH':
+            kpath = kpath+path_
+            continue
+        if keystr == '{HOST':
+            kpath = kpath + host_
+            continue
+        if keystr == '': #empty
+            continue
+        stringk = keystr.replace("{%","")
+        argsList.append(stringk)
+    KeyList = []
+    for argsL in argsList:
+        field_val = getHeaderFieldVal(request_header,argsL)
+        if field_val!=None:
+            KeyList.append(field_val)
+    rl = "".join(KeyList)+kpath
     txn = dict()
     txn["timestamp"] = ""
     txn["uuid"] = rl
     txn["request"] = request_header
     txn["response"] = response_header
     absFilepath = os.path.join(self.Variables.DataDir, filename)
-    addTransactionToSession(txn,absFilepath)
-    #absFilepath=os.path.abspath(filename)
-    #self.Setup.CopyAs(absFilepath,self.Variables.DataDir)
+    addTransactionToSession(txn, absFilepath)
+    # absFilepath=os.path.abspath(filename)
+    # self.Setup.CopyAs(absFilepath,self.Variables.DataDir)
     return
 
-#adds transaction in json format to the specified file
-def addTransactionToSession(txn,JFile):
-    jsondata=None
+# adds transaction in json format to the specified file
+
+
+def addTransactionToSession(txn, JFile):
+    jsondata = None
     if not os.path.exists(os.path.dirname(JFile)):
         os.makedirs(os.path.dirname(JFile))
     if os.path.exists(JFile):
-        jf = open(JFile,'r')
+        jf = open(JFile, 'r')
         jsondata = json.load(jf)
 
     if jsondata == None:
         jsondata = dict()
-        jsondata["version"]='0.1'
-        jsondata["timestamp"]="1234567890.098"
-        jsondata["encoding"]="url_encoded"
-        jsondata["txns"]=list()
+        jsondata["version"] = '0.1'
+        jsondata["timestamp"] = "1234567890.098"
+        jsondata["encoding"] = "url_encoded"
+        jsondata["txns"] = list()
         jsondata["txns"].append(txn)
     else:
         jsondata["txns"].append(txn)
-    with open(JFile,'w+') as jf:
+    with open(JFile, 'w+') as jf:
         jf.write(json.dumps(jsondata))
 
 
-#make headers with the key and values provided
-def makeHeader(self,requestString, **kwargs):
-    headerStr = requestString+'\r\n'
-    for k,v in kwargs.iteritems():
-        headerStr += k+': '+v+'\r\n'
-    headerStr = headerStr+'\r\n'
+# make headers with the key and values provided
+def makeHeader(self, requestString, **kwargs):
+    headerStr = requestString + '\r\n'
+    for k, v in kwargs.iteritems():
+        headerStr += k + ': ' + v + '\r\n'
+    headerStr = headerStr + '\r\n'
     return headerStr
 
 
-def MakeOriginServer(obj, name,public_ip=False,options={}):
-    server_path= os.path.join(obj.Variables.AtsTestToolsDir,'microServer/uWServer.py')
+def MakeOriginServer(obj, name, port=False, ip=False, delay=False, ssl=False, lookup_key='{PATH}', options={}):
+    server_path = os.path.join(obj.Variables.AtsTestToolsDir, 'microServer/uWServer.py')
     data_dir = os.path.join(obj.RunDirectory, name)
     # create Process
     p = obj.Processes.Process(name)
-    port=get_port(p,"Port")
-    command = "python3 {0} --data-dir {1} --port {2} --public {3} -m test".format(server_path, data_dir, port, public_ip)
-    for flag,value in options.items() :
-        command += " {} {}".format(flag,value)
+    if (port == False):
+        port = get_port(p, "Port")
+    if (ip == False):
+        ip = '127.0.0.1'
+    if (delay == False):
+        delay = 0
+    command = "python3 {0} --data-dir {1} --port {2} --ip_address {3} --delay {4} -m test --ssl {5} --lookupkey '{6}'".format(
+        server_path, data_dir, port, ip, delay, ssl,lookup_key)
+    for flag, value in options.items():
+        command += " {} {}".format(flag, value)
 
     # create process
     p.Command = command
     p.Setup.MakeDir(data_dir)
     p.Variables.DataDir = data_dir
-    p.Ready = When.PortOpen(port)
-    AddMethodToInstance(p,addResponse)
-    AddMethodToInstance(p,addTransactionToSession)
+    p.Variables.lookup_key = lookup_key
+    p.Ready = When.PortOpen(port, ip)
+    p.ReturnCode = Any(None,0)
+    AddMethodToInstance(p, addResponse)
+    AddMethodToInstance(p, addTransactionToSession)
 
     return p
 
-AddTestRunSet(MakeOriginServer,name="MakeOriginServer")
-AddTestRunSet(MakeOriginServer,name="MakeOrigin")
+
+ExtendTest(MakeOriginServer, name="MakeOriginServer")
+ExtendTest(MakeOriginServer, name="MakeOrigin")
+
diff --git a/tests/gold_tests/autest-site/ports.py b/tests/gold_tests/autest-site/ports.py
index 1f26e7e..7932be8 100644
--- a/tests/gold_tests/autest-site/ports.py
+++ b/tests/gold_tests/autest-site/ports.py
@@ -19,6 +19,7 @@
 import socket
 import subprocess
 import os
+import platform
 
 import hosts.output as host
 
@@ -59,11 +60,21 @@ def setup_port_queue(amount=1000):
         return
     try:
         # some docker setups don't have sbin setup correctly
-        new_env= os.environ.copy()
-        new_env['PATH']="/sbin:/usr/sbin:"+new_env['PATH']
-        dmin, dmax = subprocess.check_output(
-            ["sysctl", "net.ipv4.ip_local_port_range"],
-            env=new_env
+        new_env = os.environ.copy()
+        new_env['PATH'] = "/sbin:/usr/sbin:" + new_env['PATH']
+        if 'Darwin' == platform.system():
+            dmin = subprocess.check_output(
+                ["sysctl", "net.inet.ip.portrange.first"],
+                env=new_env
+            ).decode().split(":")[1].split()[0]
+            dmax = subprocess.check_output(
+                ["sysctl", "net.inet.ip.portrange.last"],
+                env=new_env
+            ).decode().split(":")[1].split()[0]
+        else:
+            dmin, dmax = subprocess.check_output(
+                ["sysctl", "net.ipv4.ip_local_port_range"],
+                env=new_env
             ).decode().split("=")[1].split()
         dmin = int(dmin)
         dmax = int(dmax)
diff --git a/tests/gold_tests/autest-site/setup.cli.ext b/tests/gold_tests/autest-site/setup.cli.ext
index 6f38a87..7fe26f7 100644
--- a/tests/gold_tests/autest-site/setup.cli.ext
+++ b/tests/gold_tests/autest-site/setup.cli.ext
@@ -16,34 +16,67 @@
 #  See the License for the specific language governing permissions and
 #  limitations under the License.
 
-import json, subprocess
+import json
+import subprocess
 import pprint
 
 if Arguments.ats_bin is not None:
     # Add environment variables
     ENV['ATS_BIN'] = Arguments.ats_bin
-    #if Arguments.ats_bin not in ENV['PATH']:
-        #ENV['PATH'] = Arguments.ats_bin + ':' + ENV['PATH']
-    
+
 if ENV['ATS_BIN'] is not None:
     # Add variables for Tests
     traffic_layout = os.path.join(ENV['ATS_BIN'], "traffic_layout")
+    tsxs = os.path.join(ENV['ATS_BIN'], "tsxs")
     if not os.path.isdir(ENV['ATS_BIN']):
         host.WriteError("--ats-bin requires a directory", show_stack=False)
+    # setting up data from traffic_layout
+    # this is getting layout structure
     if not os.path.isfile(traffic_layout):
         host.WriteError("traffic_layout is not found. Aborting tests - Bad build or install.", show_stack=False)
     try:
         out = subprocess.check_output([traffic_layout, "--json"])
     except subprocess.CalledProcessError:
-        host.WriteError("traffic_layout is broken. Aborting tests - The build of traffic server is bad.", show_stack=False) 
+        host.WriteError("traffic_layout is broken. Aborting tests - The build of traffic server is bad.", show_stack=False)
+    out = json.loads(out.decode("utf-8"))
+    for k, v in out.items():
+        out[k] = v[:-1] if v.endswith('/') else v
+    Variables.update(out)
+    host.WriteVerbose(['ats'], "Traffic server layout Data:\n", pprint.pformat(out))
+    # if the above worked this should as well
+    # this gets feature data
+    out = subprocess.check_output([traffic_layout, "-f", "--json"])
     out = json.loads(out.decode("utf-8"))
-    for k,v in out.items():
-        out[k]=v[:-1] if v.endswith('/') else v
     Variables.update(out)
-    host.WriteVerbose(['ats'],"Traffic server layout Data:\n",pprint.pformat(out))
+    host.WriteVerbose(['ats'], "Traffic server feature data:\n", pprint.pformat(out))
 
-Variables.AtsTestToolsDir = os.path.join(AutestSitePath,'../../tools')
+    # update version number 
+    out = subprocess.check_output([traffic_layout, "--version"]) 
+    out = Version(out.decode("utf-8").split("-")[2].strip()) 
+    Variables.trafficserver_version = out
+    host.WriteVerbose(['ats'], "Traffic server version:", out) 
+
+    # this querys tsxs for build flags so we can build code for the tests and get certain
+    # useful flags as which openssl to use when we don't use the system version
+    out = {
+        'CPPFLAGS': '',
+        'LIBS': '',
+        'LDFLAGS': '',
+        'CXX': ''
+    }
+    if os.path.isfile(tsxs):
+        for flag in out.keys():
+            try:
+                data = subprocess.check_output([tsxs, "-q", flag])
+                out[flag] = data.decode("utf-8")[:-1]
+            except subprocess.CalledProcessError:
+                # error if something goes wrong as the test will break if this exists and is broken
+                host.WriteError("tsxs is broken. Aborting tests", show_stack=False)
+    host.WriteVerbose(['ats'], "Traffic server build flags:\n", pprint.pformat(out))
+    Variables.update(out)
+Variables.AtsTestToolsDir = os.path.join(AutestSitePath, '../../tools')
 
 # modify delay times as we always have to kill Trafficserver
 # no need to wait
-Variables.Autest.StopProcessLongDelaySeconds=0
+Variables.Autest.StopProcessLongDelaySeconds = 0
+Variables.Autest.KillDelaySecond = 30
diff --git a/tests/gold_tests/autest-site/trafficserver.test.ext b/tests/gold_tests/autest-site/trafficserver.test.ext
index 1090ae2..35c13d7 100644
--- a/tests/gold_tests/autest-site/trafficserver.test.ext
+++ b/tests/gold_tests/autest-site/trafficserver.test.ext
@@ -269,8 +269,10 @@ def MakeATSProcess(obj, name, command='traffic_server', select_ports=True):
     p.Env['PROXY_CONFIG_ADMIN_AUTOCONF_PORT'] = str(
         p.Variables.admin_port)  # support pre ATS 6.x
 
-    # since we always kill this
-    p.ReturnCode = None
+    if command == "traffic_manager":
+        p.ReturnCode = 2
+    else:
+        p.ReturnCode = 0
 
     return p
 
diff --git a/tests/gold_tests/autest-site/trafficserver_plugins.test.ext b/tests/gold_tests/autest-site/trafficserver_plugins.test.ext
index 9ba2718..0efe6a3 100644
--- a/tests/gold_tests/autest-site/trafficserver_plugins.test.ext
+++ b/tests/gold_tests/autest-site/trafficserver_plugins.test.ext
@@ -31,14 +31,25 @@ def prepare_plugin(self, path, tsproc, plugin_args = ""):
     plugin_dir = tsproc.Env['PROXY_CONFIG_PLUGIN_PLUGIN_DIR']
     tsproc.Setup.Copy(path, plugin_dir)
 
+    tsxs = os.path.join(self.Variables.BINDIR,'tsxs')
+    # get the top level object ( ie Test) to add a condition
+    # need to change this API in AuTest to be a better name as it now has value 
+    # to be called by user API - dragon512
+    self._RootRunable.SkipUnless(
+        Condition.HasProgram(tsxs, "tsxs needs be installed with trafficserver package for this test to run")
+        )
+
     # Compile the plugin.
     in_basename = os.path.basename(path)
     in_path = os.path.join(plugin_dir, in_basename)
     out_basename = os.path.splitext(in_basename)[0] + '.so'
     out_path = os.path.join(plugin_dir, out_basename)
-    tsproc.Setup.RunCommand("tsxs -c {0} -o {1}".format(in_path, out_path))
+    tsproc.Setup.RunCommand("{tsxs} -c {0} -o {1}".format(in_path, out_path, tsxs=tsxs))
 
     # Add an entry to plugin.config.
     tsproc.Disk.plugin_config.AddLine("{0} {1}".format(out_basename,plugin_args))
 
+# remove this later
 ExtendTest(prepare_plugin, name="prepare_plugin")
+
+ExtendTest(prepare_plugin, name="PreparePlugin")
diff --git a/tests/tools/microServer/uWServer.py b/tests/tools/microServer/uWServer.py
index 0ee4ac6..b646608 100644
--- a/tests/tools/microServer/uWServer.py
+++ b/tests/tools/microServer/uWServer.py
@@ -33,8 +33,9 @@ import argparse
 import ssl
 import socket
 import importlib.util
-
+import time
 test_mode_enabled = True
+lookup_key_ = "{PATH}"
 __version__ = "1.0"
 
 
@@ -51,6 +52,7 @@ import sessionvalidation.sessionvalidation as sv
 
 
 SERVER_PORT = 5005  # default port
+SERVER_DELAY = 0 # default delay
 HTTP_VERSION = 'HTTP/1.1'
 G_replay_dict = {}
 
@@ -151,6 +153,7 @@ class SSLServer(ThreadingMixIn, HTTPServer):
 
         self.server_bind()
         self.server_activate()
+        print("Port Configured for SSL communication")
 
 
 class MyHandler(BaseHTTPRequestHandler):
@@ -166,17 +169,43 @@ class MyHandler(BaseHTTPRequestHandler):
         else:
             readChunks()
 
-    def getTestName(self, requestline):
-        key = None
-        keys = requestline.split(" ")
-        # print(keys)
-        if keys:
-            rkey = keys[1]
-        key = rkey.split("/", 1)[1]
-        if key + "/" in G_replay_dict:
-            key = key + "/"
-        elif len(key) > 1 and key[:-1] in G_replay_dict:
-            key = key[:-1]
+    def getLookupKey(self, requestline):
+        global lookup_key_
+        kpath= ""
+        path = ""
+        url_part = requestline.split(" ")
+        if url_part:
+            if url_part[1].startswith("http"):
+                path = url_part[1].split("/",2)[2]
+                host_, path = path.split("/",1)
+            else:
+                path = url_part[1].split("/",1)[1]
+        argsList = []
+        keyslist = lookup_key_.split("}")
+        for keystr in keyslist:            
+            if keystr == '{PATH':
+                kpath = kpath+path
+                continue # do not include path in the list of header fields
+            if keystr == '{HOST':
+                kpath = kpath+host_
+                continue
+            stringk = keystr.replace("{%","")
+            argsList.append(stringk)
+        KeyList = []
+        for argsL in argsList:
+            print("args",argsL,len(argsL))
+            if len(argsL)>0:
+                val = self.headers.get(argsL)
+                if val:
+                    field_val,__ = cgi.parse_header(val)
+                else:
+                    field_val=None
+                if field_val!=None:
+                    KeyList.append(field_val)
+        key = "".join(KeyList)+kpath
+        print("lookup key",key, len(key))
+
+
         return key
 
     def parseRequestline(self, requestline):
@@ -196,8 +225,11 @@ class MyHandler(BaseHTTPRequestHandler):
         return int(header.split(' ')[1])
 
     def generator(self):
-        yield 'microserver'
-        yield 'yahoo'
+        yield 'micro'
+        yield 'server'
+        yield 'apache'
+        yield 'traffic'
+        yield 'server'
 
     def send_response(self, code, message=None):
         ''' Override `send_response()`'s tacking on of server and date header lines. '''
@@ -364,7 +396,8 @@ class MyHandler(BaseHTTPRequestHandler):
     def do_GET(self):
         global G_replay_dict, test_mode_enabled
         if test_mode_enabled:
-            request_hash = self.getTestName(self.requestline)
+            time.sleep(time_delay)
+            request_hash = self.getLookupKey(self.requestline)
         else:
             request_hash, __ = cgi.parse_header(self.headers.get('Content-MD5'))
         # print("key:",request_hash)
@@ -439,7 +472,7 @@ class MyHandler(BaseHTTPRequestHandler):
     def do_HEAD(self):
         global G_replay_dict, test_mode_enabled
         if test_mode_enabled:
-            request_hash = self.getTestName(self.requestline)
+            request_hash = self.getLookupKey(self.requestline)
         else:
             request_hash, __ = cgi.parse_header(self.headers.get('Content-MD5'))
 
@@ -477,7 +510,7 @@ class MyHandler(BaseHTTPRequestHandler):
         chunkedResponse = False
         global G_replay_dict, test_mode_enabled
         if test_mode_enabled:
-            request_hash = self.getTestName(self.requestline)
+            request_hash = self.getLookupKey(self.requestline)
         else:
             request_hash, __ = cgi.parse_header(self.headers.get('Content-MD5'))
         try:
@@ -599,12 +632,6 @@ def main():
                         help="Directory with data file"
                         )
 
-    parser.add_argument("--public", "-P",
-                        type=_bool,
-                        default=False,
-                        help="Bind server to public IP 0.0.0.0 vs private IP of 127.0.0.1"
-                        )
-
     parser.add_argument("--ip_address", "-ip",
                         type=str,
                         default='',
@@ -616,6 +643,11 @@ def main():
                         default=SERVER_PORT,
                         help="Port to use")
 
+    parser.add_argument("--delay", "-dy",
+                        type=float,
+                        default=SERVER_DELAY,
+                        help="Response delay")
+
     parser.add_argument("--timeout", "-t",
                         type=float,
                         default=None,
@@ -627,10 +659,10 @@ def main():
                         type=str,
                         default="test",
                         help="Mode of operation")
-    parser.add_argument("--connection", "-c",
+    parser.add_argument("--ssl", "-ssl",
                         type=str,
-                        default="nonSSL",
-                        help="use SSL")
+                        default="False",
+                        help="SSL port")
     parser.add_argument("--key", "-k",
                         type=str,
                         default="ssl/server.pem",
@@ -648,9 +680,20 @@ def main():
                         type=str,
                         default='',
                         help="A file which will install observers on hooks")
+    parser.add_argument("--lookupkey",
+                        type=str,
+                        default="{PATH}",
+                        help="format string used as a key for response lookup: \
+                        example: \"{%Host}{%Server}{PATH}\", \"{HOST}{PATH}\", \"{PATH}\"\
+                        All the args preceded by % are header fields in the request\
+                        The only two acceptable arguments which are not header fields are : fqdn (represented by HOST) and the url path (represented by PATH) in a request line.\
+                        Example: given a client request as  << GET /some/resource/location HTTP/1.1\nHost: hahaha.com\n\n >>, if the user wishes the host field and the path to be used for the response lookup\
+                        then the required format will be {%Host}{PATH}")
 
     args = parser.parse_args()
     options = args
+    global time_delay
+    time_delay = options.delay
 
     # set up global dictionary of {uuid (string): response (Response object)}
     s = sv.SessionValidator(args.data_dir)
@@ -661,9 +704,10 @@ def main():
     try:
         socket_timeout = args.timeout
         test_mode_enabled = args.mode == "test"
-
+        global lookup_key_
+        lookup_key_ = args.lookupkey
         MyHandler.protocol_version = HTTP_VERSION
-        if options.connection == 'ssl':
+        if options.ssl == "True" or options.ssl == "true":
             server = SSLServer((options.ip_address, options.port), MyHandler, options)
         else:
             server = ThreadingServer((options.ip_address, options.port), MyHandler, options)

-- 
To stop receiving notification emails like this one, please contact
"commits@trafficserver.apache.org" <co...@trafficserver.apache.org>.