You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@trafficserver.apache.org by bc...@apache.org on 2020/10/13 22:05:56 UTC

[trafficserver] branch 9.0.x updated: Introduce proxy-verifier to AuTests (#7274)

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

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


The following commit(s) were added to refs/heads/9.0.x by this push:
     new 5ec9efb  Introduce proxy-verifier to AuTests (#7274)
5ec9efb is described below

commit 5ec9efb351ca3359ac3f9073870d119faa168c21
Author: Brian Neradt <br...@gmail.com>
AuthorDate: Tue Oct 13 17:05:45 2020 -0500

    Introduce proxy-verifier to AuTests (#7274)
    
    This adds the proxy-verifier client and server to the Traffic Server
    autests. log-filter.test.py is modified to make use of proxy-verifier.
    
    (cherry picked from commit 2e179c7ad55bee5e2240e35215c61ae46959b781)
---
 .gitignore                                         |   1 +
 tests/autest.sh                                    |   4 +-
 tests/gold_tests/autest-site/init.cli.ext          |   4 +
 tests/gold_tests/autest-site/setup.cli.ext         |  37 ++++-
 .../autest-site/verifier_client.test.ext           | 155 ++++++++++++++++++
 .../autest-site/verifier_common.py}                |  30 ++--
 .../autest-site/verifier_server.test.ext           | 181 +++++++++++++++++++++
 tests/gold_tests/logging/gold/filter-test.gold     |  10 +-
 tests/gold_tests/logging/log-filter.replays.yaml   |  52 ++++++
 tests/gold_tests/logging/log-filter.test.py        |  70 +-------
 tests/prepare_proxy_verifier.sh                    |  85 ++++++++++
 tests/tools/proxy-verifier/ssl/ca.pem              |  24 +++
 tests/tools/proxy-verifier/ssl/client.pem          |  49 ++++++
 tests/tools/proxy-verifier/ssl/server.pem          |  49 ++++++
 14 files changed, 668 insertions(+), 83 deletions(-)

diff --git a/.gitignore b/.gitignore
index 493a99c..49c9f83 100644
--- a/.gitignore
+++ b/.gitignore
@@ -193,6 +193,7 @@ RELEASE
 
 # autest
 tests/env-test/
+tests/proxy-verifier
 tests/Pipfile.lock
 tests/gold_tests/chunked_encoding/smuggle-client
 tests/gold_tests/tls/ssl-post
diff --git a/tests/autest.sh b/tests/autest.sh
index 36d4afb..289e157 100755
--- a/tests/autest.sh
+++ b/tests/autest.sh
@@ -1,4 +1,5 @@
 #!/bin/bash
+# vim: sw=4:ts=4:softtabstop=4:ai:et
 
 #  Licensed to the Apache Software Foundation (ASF) under one
 #  or more contributor license agreements.  See the NOTICE file
@@ -16,9 +17,10 @@
 #  See the License for the specific language governing permissions and
 #  limitations under the License.
 
+./prepare_proxy_verifier.sh
 pushd $(dirname $0) > /dev/null
 export PYTHONPATH=$(pwd):$PYTHONPATH
-./test-env-check.sh;
+./test-env-check.sh
 # this is for rhel or centos systems
 echo "Environment config finished. Running AuTest..."
 pipenv run autest -D gold_tests "$@"
diff --git a/tests/gold_tests/autest-site/init.cli.ext b/tests/gold_tests/autest-site/init.cli.ext
index 23a30f1..77678f1 100644
--- a/tests/gold_tests/autest-site/init.cli.ext
+++ b/tests/gold_tests/autest-site/init.cli.ext
@@ -39,3 +39,7 @@ Settings.path_argument(["--ats-bin"],
 Settings.path_argument(["--build-root"],
                        required=False,
                        help="The location of the build root for out of source builds")
+
+Settings.path_argument(["--proxy-verifier-bin"],
+                       required=False,
+                       help="A location for system proxy-verifier binaries to test with.")
diff --git a/tests/gold_tests/autest-site/setup.cli.ext b/tests/gold_tests/autest-site/setup.cli.ext
index 6c7913e..14b14fd 100644
--- a/tests/gold_tests/autest-site/setup.cli.ext
+++ b/tests/gold_tests/autest-site/setup.cli.ext
@@ -21,6 +21,10 @@ import os
 from os.path import dirname
 import pprint
 import subprocess
+import shutil
+
+test_root = dirname(dirname(AutestSitePath))
+repo_root = dirname(test_root)
 
 if Arguments.ats_bin is not None:
     # Add environment variables
@@ -30,10 +34,40 @@ if Arguments.build_root is not None:
     ENV['BUILD_ROOT'] = Arguments.build_root
 else:
     # Assume the build root is the same directory tree as the test location.
-    ENV['BUILD_ROOT'] = dirname(dirname(dirname(AutestSitePath)))
+    ENV['BUILD_ROOT'] = repo_root
 
 host.WriteVerbose(['ats'], "Test build root: {}:".format(ENV['BUILD_ROOT']))
 
+if Arguments.proxy_verifier_bin is not None:
+    ENV['VERIFIER_BIN'] = Arguments.proxy_verifier_bin
+    host.WriteVerbose(
+        ['ats'],
+        "Expecting Proxy Verifier to be in user-supplied bin path: ",
+        ENV['VERIFIER_BIN'])
+else:
+    # No Verifier bin path was specified. First see if a Proxy Verifier was
+    # unpacked as a part of preparing for this test.
+    unpack_bin = os.path.join(test_root, 'proxy-verifier', 'unpack', 'bin')
+    if os.path.exists(os.path.join(unpack_bin, 'verifier-client')):
+        ENV['VERIFIER_BIN'] = unpack_bin
+        host.WriteVerbose(
+            ['ats'],
+            "Using locally unpacked Proxy Verifier: ",
+            ENV['VERIFIER_BIN'])
+    else:
+        # Finally check the PATH.
+        path_search = shutil.which('verifier-client')
+        if path_search is not None:
+            ENV['VERIFIER_BIN'] = dirname(path_search)
+            host.WriteVerbose(
+                ['ats'],
+                "Using Proxy Verifier found in PATH: ",
+                ENV['VERIFIER_BIN'])
+        else:
+            prepare_proxy_verifier_path = os.path.join(test_root, "prepare_proxy_verifier.sh")
+            host.WriteError("Could not find Proxy Verifier binaries. "
+                            "Try running: ", prepare_proxy_verifier_path)
+
 if ENV['ATS_BIN'] is not None:
     # Add variables for Tests
     traffic_layout = os.path.join(ENV['ATS_BIN'], "traffic_layout")
@@ -91,6 +125,7 @@ if ENV['ATS_BIN'] is not None:
 
 Variables.AtsExampleDir = os.path.join(AutestSitePath, '..', '..', '..', 'example')
 Variables.AtsTestToolsDir = os.path.join(AutestSitePath, '..', '..', 'tools')
+Variables.VerifierBinPath = ENV['VERIFIER_BIN']
 Variables.BuildRoot = ENV['BUILD_ROOT']
 Variables.AtsTestPluginsDir = os.path.join(Variables.BuildRoot, 'tests', 'tools', 'plugins', '.libs')
 Variables.AtsBuildGoldTestsDir = os.path.join(Variables.BuildRoot, 'tests', 'gold_tests')
diff --git a/tests/gold_tests/autest-site/verifier_client.test.ext b/tests/gold_tests/autest-site/verifier_client.test.ext
new file mode 100755
index 0000000..5d96fff
--- /dev/null
+++ b/tests/gold_tests/autest-site/verifier_client.test.ext
@@ -0,0 +1,155 @@
+'''
+Implement the Proxy Verifier client extensions.
+'''
+#  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
+from verifier_common import create_address_argument
+
+
+def _configure_client(obj, process, name, replay_path, http_ports=None,
+                      https_ports=None, keys=None, ssl_cert='', ca_cert='',
+                      other_args='--verbose diag'):
+    """
+    Configure the process for running the verifier-client.
+
+    Args:
+        obj: An object that has a RunDirectory attribute.
+
+        process: (Process) The test process to configure for verifier-client.
+
+        See AddVerifierClientProcess for a description of all other arguments.
+    """
+
+    # Create the directory we will setup for the replay binaries to run under.
+    client_dir = os.path.join(obj.RunDirectory, name)
+
+    # Create a link of the binary to the rundir and set up the PATH variable.
+    # This will be the verifier-client that gets run.
+    bin_dir = 'bin'
+    process.Env['CLIENT_BIN_PATH'] = bin_dir
+    bin_path = os.path.join(client_dir, bin_dir)
+    process.Env['PATH'] = bin_path + os.pathsep + process.ComposeEnv()['PATH']
+    process.Setup.Copy(process.Variables.VerifierBinPath, bin_path, CopyLogic.SoftFiles)
+
+    if http_ports is None and https_ports is None:
+        raise ValueError("http_ports and/or https_ports must be supplied.")
+
+    # Configure the verifier-client command line arguments.
+    command = "verifier-client run "
+    if replay_path:
+        # Create a copy of the replay directory in the run directory.
+        run_replay_path = os.path.join(client_dir, os.path.basename(replay_path))
+        process.Setup.Copy(replay_path, run_replay_path, CopyLogic.SoftFiles)
+        command += " {} ".format(run_replay_path)
+
+    if not http_ports:
+        http_ports = [8080]
+    if http_ports:
+        command += create_address_argument(http_ports)
+        command += " "
+
+    if not https_ports:
+        https_ports = [4443]
+    if https_ports:
+        command += create_address_argument(https_ports)
+        command += " "
+
+        if ssl_cert == '':
+            ssl_cert = os.path.join(obj.Variables["AtsTestToolsDir"],
+                                    "proxy-verifier", "ssl", "client.pem")
+
+            if not os.path.isfile(ssl_cert):
+                raise ValueError("Tried to use '{}' for --client-cert, but it is not "
+                                 "a valid file.".format(ssl_cert))
+        if ssl_cert:
+            run_ssl_cert = ssl_cert
+            if os.path.isfile(ssl_cert):
+                run_ssl_cert = os.path.join(client_dir, os.path.basename(ssl_cert))
+                process.Setup.Copy(ssl_cert, run_ssl_cert, CopyLogic.SoftFiles)
+            command += ' --client-cert "{}" '.format(run_ssl_cert)
+
+        if ca_cert == '':
+            ca_cert = os.path.join(obj.Variables["AtsTestToolsDir"],
+                                   "proxy-verifier", "ssl", "ca.pem")
+
+            if not os.path.isfile(ca_cert):
+                raise ValueError("Tried to use '{}' for --ca-certs, but it is not "
+                                 "a valid file.".format(ca_cert))
+        if ca_cert:
+            run_ca_cert = ca_cert
+            if os.path.isfile(ca_cert):
+                run_ca_cert = os.path.join(client_dir, os.path.basename(ca_cert))
+                process.Setup.Copy(ca_cert, run_ca_cert, CopyLogic.SoftFiles)
+            command += ' --ca-certs "{}" '.format(run_ca_cert)
+
+    if other_args:
+        command += " {}".format(other_args)
+
+    if keys is not None:
+        command += " --keys {}".format(keys)
+
+    process.Command = command
+    process.ReturnCode = 0
+
+    process.Streams.stdout = Testers.ExcludesExpression(
+        "Violation|Invalid status",
+        "There should be no Proxy Verifier violation errors.")
+
+
+def AddVerifierClientProcess(run, name, replay_path, http_ports=None,
+                             https_ports=None, keys=None, ssl_cert='', ca_cert='',
+                             other_args='--verbose diag'):
+    """
+    Set the Default process of the test run to a verifier-client Process.
+
+    Args:
+        run: (TestRun) The test run to which the client process is added.
+
+        name: (str) The name to apply to this particular verifier-client instance.
+            Individual verifier-client processes must have unique names to
+            distinguish between them.
+
+        replay_path: (path) The file or directory containing the traffic replay
+            specification.
+
+        http_ports: (list of ints) The set of HTTP ports to connect on.
+
+        https_ports: (list of ints) The set of HTTPS ports to connect on.
+
+        ssl_cert: (path) The location of the cert for HTTPS encryption. If this
+            is not provided and stock ssl_cert will be used.
+
+        ca_cert: (path) The location of the CA for HTTPS encryption. If this
+            is not provided a stock CA will be used.
+
+        other_args: (str) Any other arbitrary options to pass to verifier-client.
+
+    Returns:
+        The newly constructed verifier-client for the test run, which is also the
+        Default Process of the test run.
+    """
+
+    p = run.Processes.Default
+    _configure_client(run, p, name, replay_path, http_ports, https_ports,
+                      keys, ssl_cert, ca_cert, other_args)
+    return p
+
+
+##########################################################################
+ExtendTestRun(AddVerifierClientProcess, name="AddVerifierClientProcess")
diff --git a/tests/autest.sh b/tests/gold_tests/autest-site/verifier_common.py
old mode 100755
new mode 100644
similarity index 64%
copy from tests/autest.sh
copy to tests/gold_tests/autest-site/verifier_common.py
index 36d4afb..e15098e
--- a/tests/autest.sh
+++ b/tests/gold_tests/autest-site/verifier_common.py
@@ -1,5 +1,6 @@
-#!/bin/bash
-
+'''
+Common utilities for the Proxy Verifier extensions.
+'''
 #  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
@@ -16,12 +17,19 @@
 #  See the License for the specific language governing permissions and
 #  limitations under the License.
 
-pushd $(dirname $0) > /dev/null
-export PYTHONPATH=$(pwd):$PYTHONPATH
-./test-env-check.sh;
-# this is for rhel or centos systems
-echo "Environment config finished. Running AuTest..."
-pipenv run autest -D gold_tests "$@"
-ret=$?
-popd > /dev/null
-exit $ret
+
+def create_address_argument(ports):
+    """
+    >>> create_address_argument([8080, 8081])
+    '"127.0.0.1:8080,127.0.0.1:8081"'
+    """
+    is_first = True
+    argument = '"'
+    for port in ports:
+        if is_first:
+            is_first = False
+        else:
+            argument += ','
+        argument += "127.0.0.1:{}".format(port)
+    argument += '"'
+    return argument
diff --git a/tests/gold_tests/autest-site/verifier_server.test.ext b/tests/gold_tests/autest-site/verifier_server.test.ext
new file mode 100755
index 0000000..52cc92c
--- /dev/null
+++ b/tests/gold_tests/autest-site/verifier_server.test.ext
@@ -0,0 +1,181 @@
+'''
+Implement the Proxy Verifier test server extension.
+'''
+#  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
+from ports import get_port
+from verifier_common import create_address_argument
+
+
+def _configure_server(obj, process, name, replay_path, http_ports=None, https_ports=None,
+                      ssl_cert='', ca_cert='', other_args='--verbose diag'):
+    """
+    Configure the provided process to run a verifier-server command.
+
+    Args
+        obj: An object that has a RunDirectory attribute.
+
+        process: (Process) The test process to configure for verifier-server.
+
+        For all other arguments, see MakeVerifierServerProcess.
+    """
+    # Create the directory we will setup for the replay binaries to run under.
+    server_dir = os.path.join(obj.RunDirectory, name)
+
+    # Create a link of the binary to the rundir and set up the PATH variable.
+    # This will be the verifier-server that gets run.
+    bin_dir = 'bin'
+    process.Env['SERVER_BIN_PATH'] = bin_dir
+    bin_path = os.path.join(server_dir, bin_dir)
+    process.Env['PATH'] = bin_path + os.pathsep + process.ComposeEnv()['PATH']
+    process.Setup.Copy(process.Variables.VerifierBinPath, bin_path, CopyLogic.SoftFiles)
+
+    # Configure the verifier-server command line arguments.
+    command = "verifier-server run "
+
+    if http_ports is None:
+        get_port(process, "http_port")
+        http_ports = [process.Variables.http_port]
+
+    if len(http_ports) > 0:
+        command += "--listen "
+        command += create_address_argument(http_ports)
+        command += " "
+
+    if https_ports is None:
+        get_port(process, "https_port")
+        https_ports = [process.Variables.https_port]
+
+    if len(https_ports) > 0:
+        command += '--listen-https '
+        command += create_address_argument(https_ports)
+        command += " "
+
+        if ssl_cert == '':
+            ssl_cert = os.path.join(obj.Variables["AtsTestToolsDir"],
+                                    "proxy-verifier", "ssl", "server.pem")
+
+            if not os.path.isfile(ssl_cert):
+                raise ValueError("Tried to use '{}' for --server-cert, but it is not "
+                                 "a valid file.".format(ssl_cert))
+        if ssl_cert:
+            run_ssl_cert = ssl_cert
+            if os.path.isfile(ssl_cert):
+                run_ssl_cert = os.path.join(server_dir, os.path.basename(ssl_cert))
+                process.Setup.Copy(ssl_cert, run_ssl_cert, CopyLogic.SoftFiles)
+            command += ' --server-cert "{}" '.format(run_ssl_cert)
+
+        if ca_cert == '':
+            ca_cert = os.path.join(obj.Variables["AtsTestToolsDir"],
+                                   "proxy-verifier", "ssl", "ca.pem")
+
+            if not os.path.isfile(ca_cert):
+                raise ValueError("Tried to use '{}' for --ca-certs, but it is not "
+                                 "a valid file.".format(ca_cert))
+        if ca_cert:
+            run_ca_cert = ca_cert
+            if os.path.isfile(ca_cert):
+                run_ca_cert = os.path.join(server_dir, os.path.basename(ca_cert))
+                process.Setup.Copy(ca_cert, run_ca_cert, CopyLogic.SoftFiles)
+            command += ' --ca-certs "{}" '.format(run_ca_cert)
+
+    if replay_path:
+        # Create a copy of the replay directory in the run directory.
+        run_replay_path = os.path.join(server_dir, os.path.basename(replay_path))
+        process.Setup.Copy(replay_path, run_replay_path, CopyLogic.SoftFiles)
+        command += "{} ".format(run_replay_path)
+    if other_args:
+        command += "{} ".format(other_args)
+    process.Command = command
+
+    process.Ready = When.PortOpenv4(process.Variables.http_port)
+    process.ReturnCode = 0
+
+    process.Streams.stdout = Testers.ExcludesExpression(
+        "Violation",
+        "There should be no Proxy Verifier violation errors.")
+
+
+def MakeVerifierServerProcess(test, name, replay_path, http_ports=None,
+                              https_ports=None, ssl_cert='', ca_cert='',
+                              other_args='--verbose diag'):
+    """
+    Create a verifier-server process for the Test.
+
+    Args:
+        test: (Test) The Test object being updated with the server process.
+
+        name: (str) The name to apply to this particular verifier-server instance.
+            Individual verifier-server processes must have unique names to
+            distinguish between them.
+
+        replay_path: (path) The file or directory containing the traffic replay
+            specification.
+
+        http_ports: (list of ints) The set of HTTP ports to listen on. If not
+            passed in, a single open port will be selected.
+
+        https_ports: (list of ints) The set of HTTPS ports to listen on. If not
+            passed in, a single open port will be selected.
+
+        ssl_cert: (path) The location of the cert for HTTPS encryption. If this
+            is not provided and stock ssl_cert will be used.
+
+        ca_cert: (path) The location of the CA for HTTPS encryption. If this
+            is not provided a stock CA will be used.
+
+        other_args: (str) Any other arbitrary options to pass to verifier-server.
+
+    Raises:
+        ValueError if https_ports is non-empty and a valid ssl_cert could not
+            be derived.
+    """
+    server = test.Processes.Process(name)
+    _configure_server(test, server, name, replay_path, http_ports, https_ports,
+                      ssl_cert, ca_cert, other_args)
+    return server
+
+
+def AddVerifierServerProcess(run, name, replay_path, http_ports=None,
+                             https_ports=None, ssl_cert='', ca_cert='',
+                             other_args='--verbose diag'):
+    """
+    Create a verifier-server process and configure it for the given TestRun.
+
+    Args:
+        run: (TestRun) The test run to which the server process is added.
+
+        For all other arguments, see MakeVerifierServerProcess.
+
+    Returns:
+        The newly created server process.
+    """
+
+    server = run.Processes.Process(name)
+    _configure_server(run, server, name, replay_path, http_ports, https_ports,
+                      ssl_cert, ca_cert, other_args)
+
+    client = run.Processes.Default
+    client.StartBefore(server)
+
+    return server
+
+
+##########################################################################
+ExtendTest(MakeVerifierServerProcess, name="MakeVerifierServerProcess")
+ExtendTestRun(AddVerifierServerProcess, name="AddVerifierServerProcess")
diff --git a/tests/gold_tests/logging/gold/filter-test.gold b/tests/gold_tests/logging/gold/filter-test.gold
index 9dc6586..7465c05 100644
--- a/tests/gold_tests/logging/gold/filter-test.gold
+++ b/tests/gold_tests/logging/gold/filter-test.gold
@@ -1,5 +1,5 @@
-http://test-1/test-1?name=value&email=XXXXXXXXXXXXX
-http://test-2/test-2?email=XXXXXXXXXXXXX&name=password
-http://test-3/test-3?trivial=password&name1=val1&email=XXXXXXXXXXXXX
-http://test-4/test-4?trivial=password&email=&name=handle&session_redirect=XXXXXXXXXXXX
-http://test-5/test-5?trivial=password&email=XXXXXXXXXXXXX&email=XXXXXXXXXXXXX&session_redirect=XXXXXXXXXXXX&email=XXXXXXXXXXXXX&name=value
+http://example.com/test-1?name=value&email=XXXXXXXXXXXXX
+http://example.com/test-2?email=XXXXXXXXXXXXX&name=password
+http://example.com/test-3?trivial=password&name1=val1&email=XXXXXXXXXXXXX
+http://example.com/test-4?trivial=password&email=&name=handle&session_redirect=XXXXXXXXXXXX
+http://example.com/test-5?trivial=password&email=XXXXXXXXXXXXX&email=XXXXXXXXXXXXX&session_redirect=XXXXXXXXXXXX&email=XXXXXXXXXXXXX&name=value
diff --git a/tests/gold_tests/logging/log-filter.replays.yaml b/tests/gold_tests/logging/log-filter.replays.yaml
new file mode 100644
index 0000000..3b87bb1
--- /dev/null
+++ b/tests/gold_tests/logging/log-filter.replays.yaml
@@ -0,0 +1,52 @@
+meta:
+  version: "1.0"
+
+  blocks:
+  - request_base: &request_base
+      method: "GET"
+      version: "1.1"
+      scheme: "http"
+      headers:
+        fields:
+        - [ Host, example.com ]
+  - 200_response: &200_response
+      server-response:
+        status: 200
+        reason: OK
+        headers:
+          fields:
+          - [ Content-Length, 0 ]
+      proxy-response:
+        status: 200
+
+sessions:
+- transactions:
+  - all: { headers: { fields: [[ uuid, test-1 ]]}}
+    client-request:
+      url: "/test-1?name=value&email=123@gmail.com"
+      <<: *request_base
+    <<: *200_response
+
+  - all: { headers: { fields: [[ uuid, test-2 ]]}}
+    client-request:
+      url: "/test-2?email=123@gmail.com&name=password"
+      <<: *request_base
+    <<: *200_response
+
+  - all: { headers: { fields: [[ uuid, test-3 ]]}}
+    client-request:
+      url: "/test-3?trivial=password&name1=val1&email=123@gmail.com"
+      <<: *request_base
+    <<: *200_response
+
+  - all: { headers: { fields: [[ uuid, test-4 ]]}}
+    client-request:
+      url: "/test-4?trivial=password&email=&name=handle&session_redirect=wiped_string"
+      <<: *request_base
+    <<: *200_response
+
+  - all: { headers: { fields: [[ uuid, test-5 ]]}}
+    client-request:
+      url: "/test-5?trivial=password&email=123@gmail.com&email=456@gmail.com&session_redirect=wiped_string&email=789@gmail.com&name=value"
+      <<: *request_base
+    <<: *200_response
diff --git a/tests/gold_tests/logging/log-filter.test.py b/tests/gold_tests/logging/log-filter.test.py
index ea4b162..95c1aaf 100644
--- a/tests/gold_tests/logging/log-filter.test.py
+++ b/tests/gold_tests/logging/log-filter.test.py
@@ -23,42 +23,8 @@ Test log filter.
 '''
 
 ts = Test.MakeATSProcess("ts")
-server = Test.MakeOriginServer("server")
-
-request_header = {'timestamp': 100, "headers": "GET /test-1 HTTP/1.1\r\nHost: test-1\r\n\r\n", "body": ""}
-response_header = {
-    'timestamp': 100,
-    "headers": "HTTP/1.1 200 OK\r\nTest: 1\r\nContent-Type: application/json\r\nConnection: close\r\nContent-Type: application/json\r\n\r\n",
-    "body": "Test 1"}
-server.addResponse("sessionlog.json", request_header, response_header)
-server.addResponse("sessionlog.json",
-                   {'timestamp': 101,
-                    "headers": "GET /test-2 HTTP/1.1\r\nHost: test-2\r\n\r\n",
-                    "body": ""},
-                   {'timestamp': 101,
-                       "headers": "HTTP/1.1 200 OK\r\nTest: 2\r\nContent-Type: application/jason\r\nConnection: close\r\nContent-Type: application/json\r\n\r\n",
-                       "body": "Test 2"})
-server.addResponse("sessionlog.json",
-                   {'timestamp': 102,
-                    "headers": "GET /test-3 HTTP/1.1\r\nHost: test-3\r\n\r\n",
-                    "body": ""},
-                   {'timestamp': 102,
-                       "headers": "HTTP/1.1 200 OK\r\nTest: 3\r\nConnection: close\r\nContent-Type: application/json\r\n\r\n",
-                       "body": "Test 3"})
-server.addResponse("sessionlog.json",
-                   {'timestamp': 103,
-                    "headers": "GET /test-4 HTTP/1.1\r\nHost: test-4\r\n\r\n",
-                    "body": ""},
-                   {'timestamp': 103,
-                       "headers": "HTTP/1.1 200 OK\r\nTest: 4\r\nConnection: close\r\nContent-Type: application/json\r\n\r\n",
-                       "body": "Test 4"})
-server.addResponse("sessionlog.json",
-                   {'timestamp': 104,
-                    "headers": "GET /test-5 HTTP/1.1\r\nHost: test-5\r\n\r\n",
-                    "body": ""},
-                   {'timestamp': 104,
-                       "headers": "HTTP/1.1 200 OK\r\nTest: 5\r\nConnection: close\r\nContent-Type: application/json\r\n\r\n",
-                       "body": "Test 5"})
+replay_file = "log-filter.replays.yaml"
+server = Test.MakeVerifierServerProcess("server", replay_file)
 
 ts.Disk.records_config.update({
     'proxy.config.net.connections_throttle': 100,
@@ -66,7 +32,7 @@ ts.Disk.records_config.update({
 })
 # setup some config file for this server
 ts.Disk.remap_config.AddLine(
-    'map / http://localhost:{}/'.format(server.Variables.Port)
+    'map / http://localhost:{}/'.format(server.Variables.http_port)
 )
 
 ts.Disk.logging_yaml.AddLines(
@@ -94,36 +60,10 @@ logging:
 Test.Disk.File(os.path.join(ts.Variables.LOGDIR, 'filter-test.log'),
                exists=True, content='gold/filter-test.gold')
 
-# first test is a miss for default
 tr = Test.AddTestRun()
-# Wait for the micro server
 tr.Processes.Default.StartBefore(server)
-# Delay on readiness of our ssl ports
-tr.Processes.Default.StartBefore(Test.Processes.ts)
-
-tr.Processes.Default.Command = 'curl --verbose --header "Host: test-1" "http://localhost:{0}/test-1?name=value&email=123@gmail.com"' .format(
-    ts.Variables.port)
-tr.Processes.Default.ReturnCode = 0
-
-tr = Test.AddTestRun()
-tr.Processes.Default.Command = 'curl --verbose --header "Host: test-2" "http://localhost:{0}/test-2?email=123@gmail.com&name=password"' .format(
-    ts.Variables.port)
-tr.Processes.Default.ReturnCode = 0
-
-tr = Test.AddTestRun()
-tr.Processes.Default.Command = 'curl --verbose --header "Host: test-3" "http://localhost:{0}/test-3?trivial=password&name1=val1&email=123@gmail.com"' .format(
-    ts.Variables.port)
-tr.Processes.Default.ReturnCode = 0
-
-tr = Test.AddTestRun()
-tr.Processes.Default.Command = 'curl --verbose --header "Host: test-4" "http://localhost:{0}/test-4?trivial=password&email=&name=handle&session_redirect=wiped_string"' .format(
-    ts.Variables.port)
-tr.Processes.Default.ReturnCode = 0
-
-tr = Test.AddTestRun()
-tr.Processes.Default.Command = 'curl --verbose --header "Host: test-5" "http://localhost:{0}/test-5?trivial=password&email=123@gmail.com&email=456@gmail.com&session_redirect=wiped_string&email=789@gmail.com&name=value"' .format(
-    ts.Variables.port)
-tr.Processes.Default.ReturnCode = 0
+tr.Processes.Default.StartBefore(ts)
+tr.AddVerifierClientProcess("client-1", replay_file, http_ports=[ts.Variables.port])
 
 tr = Test.AddTestRun()
 tr.DelayStart = 10
diff --git a/tests/prepare_proxy_verifier.sh b/tests/prepare_proxy_verifier.sh
new file mode 100755
index 0000000..6690b84
--- /dev/null
+++ b/tests/prepare_proxy_verifier.sh
@@ -0,0 +1,85 @@
+#!/bin/bash
+# vim: sw=4:ts=4:softtabstop=4:ai:et
+
+#  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.
+
+ROOT=${ROOT:-$(cd $(dirname $0) && git rev-parse --show-toplevel)}
+pv_top_dir="${ROOT}/tests/proxy-verifier"
+pv_unpack_dir="${pv_top_dir}/unpack"
+bin_dir="${pv_unpack_dir}/bin"
+pv_name="proxy-verifier"
+pv_version="v1.10.0"
+pv_dir="${pv_name}-${pv_version}"
+pv_tar_filename="${pv_dir}.tar.gz"
+pv_tar="${pv_top_dir}/${pv_tar_filename}"
+pv_tar_url="https://ci.trafficserver.apache.org/bintray/${pv_tar_filename}"
+expected_sha1="f9ad11942f9098733e0286112a3c17975ebed363"
+pv_client="${bin_dir}/verifier-client"
+pv_server="${bin_dir}/verifier-server"
+TAR=${TAR:-tar}
+CURL=${CURL:-curl}
+fail()
+{
+    echo $1
+    exit 1
+}
+# Check to see whether Proxy Verifier has already been unpacked.
+if ! [ -x ${pv_client} -a -x ${pv_server} ]
+then
+    # 1. Get the tar file if it has not been retrieved already.
+    # Note that the two spaces between the hash and ${ARCHIVE) is needed
+    if [ ! -e ${pv_tar} ]
+    then
+        # default to using native sha1sum command when available
+        if [ $(which sha1sum) ]
+        then
+            SHASUM=${SHASUM:-sha1sum}
+        else
+            SHASUM=${SHASUM:-shasum}
+        fi
+        mkdir -p ${pv_top_dir}
+        ${CURL} -L --progress-bar -o ${pv_tar} ${pv_tar_url}
+        cat > ${pv_top_dir}/sha1 << EOF
+${expected_sha1}  ${pv_tar}
+EOF
+        ${SHASUM} -c ${pv_top_dir}/sha1 || fail "SHA1 mismatch for downloaded ${pv_tar_filename}."
+    fi
+
+    # 2. Untar the Proxy Verifier binaries.
+    mkdir -p ${pv_unpack_dir}
+    ${TAR} -x -C ${pv_unpack_dir} -f ${pv_tar}
+
+    # 3. Determine the target OS.
+    pv_os_dir=""
+    case $(uname -s) in
+    Darwin)
+        pv_os_dir="${pv_unpack_dir}/${pv_dir}/mac-os"
+        ;;
+    Linux)
+        pv_os_dir="${pv_unpack_dir}/${pv_dir}/linux"
+        ;;
+    *)
+        fail "We need to build proxy-verifier for $(uname -s)"
+    esac
+
+    # 4. Link the OS-specific binaries to the bin directory.
+    mkdir -p ${bin_dir}
+    ln -s ${pv_os_dir}/verifier-client ${bin_dir}
+    ln -s ${pv_os_dir}/verifier-server ${bin_dir}
+    chmod +x ${pv_client}
+    chmod +x ${pv_server}
+fi
diff --git a/tests/tools/proxy-verifier/ssl/ca.pem b/tests/tools/proxy-verifier/ssl/ca.pem
new file mode 100644
index 0000000..fde8c54
--- /dev/null
+++ b/tests/tools/proxy-verifier/ssl/ca.pem
@@ -0,0 +1,24 @@
+-----BEGIN CERTIFICATE-----
+MIID/TCCAuWgAwIBAgIJAOF6432S3ZsOMA0GCSqGSIb3DQEBCwUAMIGTMQswCQYD
+VQQGEwJVUzELMAkGA1UECAwCSUwxDjAMBgNVBAcMBVNhdm95MQ8wDQYDVQQKDAZZ
+YWhvbyExFjAUBgNVBAsMDVRyYWZmaWNTZXJ2ZXIxEDAOBgNVBAMMB2NlcnRfY24x
+LDAqBgkqhkiG9w0BCQEWHWJyaWFuLm5lcmFkdEB2ZXJpem9ubWVkaWEuY29tMCAX
+DTIwMDYwMzIyMzU0M1oYDzIxMTgxMjI3MjIzNTQzWjCBkzELMAkGA1UEBhMCVVMx
+CzAJBgNVBAgMAklMMQ4wDAYDVQQHDAVTYXZveTEPMA0GA1UECgwGWWFob28hMRYw
+FAYDVQQLDA1UcmFmZmljU2VydmVyMRAwDgYDVQQDDAdjZXJ0X2NuMSwwKgYJKoZI
+hvcNAQkBFh1icmlhbi5uZXJhZHRAdmVyaXpvbm1lZGlhLmNvbTCCASIwDQYJKoZI
+hvcNAQEBBQADggEPADCCAQoCggEBAJ8lOELz8zxcuqTH/CszDeum6sK24S7UNnvi
+iT5Oi6x6O757S4AwRE0uBZq8l+Kt8Nt4VSfhUbfcSP1xFkD5B3yKhetC7PCFd1Tw
+6iqkYplVUextRsweOJkaP85KR3dttLZJBaW98U5Yv/wQ3WisgR+jnZBWfQHnCl+W
+NEZgdBKT292T6c4+rrGdefVscgDCEQGQVs9m9beerLmJnjEN54qrUGuF48+sTdOU
+63ud92Ftx36wMNh/l7REm8BvuCBLquKmi304h+RHwF0KoIm4E0cVkQ3ciqHM2JhX
+Uzc+aEWMPixD4WIOnY2CVSXMIR2fKOKGC0chfjpi0ppQFTNArBcCAwEAAaNQME4w
+HQYDVR0OBBYEFEUtp1nAuqOUc1JlK2gfiY3Mav8pMB8GA1UdIwQYMBaAFEUtp1nA
+uqOUc1JlK2gfiY3Mav8pMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEB
+AIDN79xRIVt6xMRbe4icKSZ5FfSJaxSanb1u5s5zQncfDMb7wEOXcwDANXbxNN7B
+R6GWk6G6cmcQ+gkXwOzGCvOv+JX2SvjkKNcNS/PfGgj4NNjSxLsUhvd1bcoNwo8E
+Pq0KHYbaL4PE4XgHWoGQ5bOxtDINcDLaPDP4FrU2JXfc1ajdbKrRxCGXwnk+Soff
+PVOl2OPcstO0+DN4vEIBop/EwBTDYu2uGQHOTq12R4xkZQB+21+16lV+wyOAiRW3
+LjhElouGkdw8GKBz0NVlVvMeYjI92Woep2Rg0YIGv9GM1S2qm/TDwn4cZ1/h/Egj
+mO1HrjDQ00MmWqjDijQT6W8=
+-----END CERTIFICATE-----
diff --git a/tests/tools/proxy-verifier/ssl/client.pem b/tests/tools/proxy-verifier/ssl/client.pem
new file mode 100644
index 0000000..6713cf9
--- /dev/null
+++ b/tests/tools/proxy-verifier/ssl/client.pem
@@ -0,0 +1,49 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEpQIBAAKCAQEA0PXTSR5BtiYAoHwElsLPd0BmjZ/kDOrM6qYcdSPi0PKdxQ1s
+saSzZDRxKeCExNTpDj4Ovlq9Qba3RyJ8JtNgjxY0DrZ4ykFrgwQNMWN+tgGd4Jlt
+/y12wadUeKpFCQQBHSEqRSqbs9DQ2I8pjhlpWe27zZKsbPZjjymUa9FJWLZ7N1Tb
+LhqahmgEqPlSbzsIUCFu+ngMTPZIAhSR+HjaRRutAfld2xXnG6r29TlqOU8osNbO
+HeGwnXS3DoLSmVrJUVdIc8QZ47pahCOP//E+UTEAMEmSwQi6soPKL0yCfa3p6Pot
+DJrmxHM43FeJkPLXvx8jPpgh0620kVobTgmFHQIDAQABAoIBAAnwNy1aGAv+wLbh
+TyKQf2ePk5EW0rTekgJzBhV4MHh5oZFWsx271KBmch9ow0fNTIxV3UOmcyvl8c+b
+T0ZVdVk42B7/BL2x4NgpYCtCLSug5g5hnb6uPeC2Aal/h6sHGrp08lq5zQ//VX+H
+R5WvlbgmO3FqkXLZQSD0/E8odBGY/j+zJfXL6ir0X09HbRSiP3oUPYYAhgCpYd01
+m9WXVaiyc2U4YPe5BZthGgewCafBVwbTmQPxKbHsPgJ5sLggU/91vMMbsRBttzfW
++g6rUMM/nU+bvP+S5r6VPkdNM1WWGt+R3Ua5o6UcYmaz6+xsHPkAiihQbK7Nm4MJ
+K4Q1OU0CgYEA7Gk/T4o1Hpqw8KyXOsy4IzBsErB3l+wFaqrGpMa6gWHmEgvH3Nm/
+3Ga03Jx0nzBK+PfUwwCevGr51LncIw7yRKuDLE5Sz5SciTEHnS5PNQ9yBaUJBUuO
+P6fTd4sPMaMI7aJodhXfRCKWiD/AwD53cimof2qi5526OJb2O9qV1c8CgYEA4kZK
+TQ++ZJtD6OVojRN+3I4yZTirHvKwwoSZ+b5rNfrFknJ5mU60ItH6LQHzlEV28LcR
+VSbGJU3VpMGUmd+Szhbxk5OKvIrX3yi2xcIpbvhKY9EPD3IJhoANzGVe2tm0eGa0
+I9HyDqdxy98rjhP6VnZgSZQtUpWw7tNSf33nXVMCgYEAnJE7X6cNdP5HzqzO3x8z
+mAJ6oIoEOjYShEkjk38Vh5hZcXwh2i7PtNzETRLE3aRzEp23Z4nilrBWUr7gfsto
+QXhBQDeC+nzWirlQ7JT92gsnnXtmFP6r75ZrI1GSN3Jc+FxFyGbF3W72uLdYJTl5
+i77xG6l4x+IasV2xJ4SlFNsCgYEAg1rktTmngEX2NVQ/zm373lOaA9LS3ANtA27w
+599X450xZqOX3Zyny/LzdX9FhNSSiIjtwe3hZzR5Cszp1C3KzmLZWJ91EaDUUpMT
+D1h4rxfqL2nkgUXlK7RYzkgmuYtaTe7pMkYla8ZetEhYw4DreZf8q5oeeWu2q933
+bVWMo0sCgYEA1+p4s3+WKc0BvSmsIvXU/KnwtgAciKndQ4Bbsr4TFlZBO6hAHjbh
+JL+R/NHxyTA+Lr9yXsa5aKh3DSBh31iHk96b8TjnxWPtUbhfO0V5496fRciybAeG
+ZDhGLrIW27F2MBPfvw4bfxIBEXmlpcdrlvTduZM9W4khwESlRHg83+k=
+-----END RSA PRIVATE KEY-----
+-----BEGIN CERTIFICATE-----
+MIIDoDCCAogCAQEwDQYJKoZIhvcNAQELBQAwgZMxCzAJBgNVBAYTAlVTMQswCQYD
+VQQIDAJJTDEOMAwGA1UEBwwFU2F2b3kxDzANBgNVBAoMBllhaG9vITEWMBQGA1UE
+CwwNVHJhZmZpY1NlcnZlcjEQMA4GA1UEAwwHY2VydF9jbjEsMCoGCSqGSIb3DQEJ
+ARYdYnJpYW4ubmVyYWR0QHZlcml6b25tZWRpYS5jb20wIBcNMjAwNjAzMjIzODE1
+WhgPMjExODEyMjcyMjM4MTVaMIGVMQswCQYDVQQGEwJVUzELMAkGA1UECAwCSUwx
+DjAMBgNVBAcMBVNhdm95MQ8wDQYDVQQKDAZZYWhvbyExFjAUBgNVBAsMDVRyYWZm
+aWNTZXJ2ZXIxEjAQBgNVBAMMCWNsaWVudF9jbjEsMCoGCSqGSIb3DQEJARYdYnJp
+YW4ubmVyYWR0QHZlcml6b25tZWRpYS5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IB
+DwAwggEKAoIBAQDQ9dNJHkG2JgCgfASWws93QGaNn+QM6szqphx1I+LQ8p3FDWyx
+pLNkNHEp4ITE1OkOPg6+Wr1BtrdHInwm02CPFjQOtnjKQWuDBA0xY362AZ3gmW3/
+LXbBp1R4qkUJBAEdISpFKpuz0NDYjymOGWlZ7bvNkqxs9mOPKZRr0UlYtns3VNsu
+GpqGaASo+VJvOwhQIW76eAxM9kgCFJH4eNpFG60B+V3bFecbqvb1OWo5Tyiw1s4d
+4bCddLcOgtKZWslRV0hzxBnjulqEI4//8T5RMQAwSZLBCLqyg8ovTIJ9reno+i0M
+mubEczjcV4mQ8te/HyM+mCHTrbSRWhtOCYUdAgMBAAEwDQYJKoZIhvcNAQELBQAD
+ggEBACYIcnbLNQbrrTdpH7DyV+ZXSy0gyn9+ilc0z7RAy4x/W8AH5CTuti+8dE7Z
+L+o2QX6me93Fe3O2IjdTVFfNKAskWabc+9eGS0mRA5KNf/UlhMFwDF/oDqeJnd0c
+4BJZz2QgVh6k4Zgzf6bznHuZsm165r22tv1k7B3babEgOlautFptbekxUEKOBMyB
+9wZm04E3gbgSfyH1s20uOeeUcgw5AreD8yZqu7bqDqG9xbE57oDD5oVEwAv4N5EV
+4U2Qw4A39WbD3rjbrW4/MF0Liwp8sdjTIwXxmM/Pa833Olg89DifxbMPzKOWGe4r
+y+UgOqoCeBEZxEzE/pnFS3mxA7w=
+-----END CERTIFICATE-----
diff --git a/tests/tools/proxy-verifier/ssl/server.pem b/tests/tools/proxy-verifier/ssl/server.pem
new file mode 100644
index 0000000..c5c4099
--- /dev/null
+++ b/tests/tools/proxy-verifier/ssl/server.pem
@@ -0,0 +1,49 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEpAIBAAKCAQEA29KRWtimtF7HRehYwMm8gxpxOcDvwUiXxiLBswEfH2gKUgp2
+8lvjfbd3eHXe57dVuXy8s/mnt/jfj8BtyEwIAIbgJnBUGM0V5JXJ2BCg8Q3loqGh
+bicDJaXnwo+ZPOWu7x5DpvHXX9HuJPUWeEwIuhtOO0BfbiDvOuPN29y7K5T0gkGl
+RxhE6jlnNN/xg+1IDu10+8ISqGxr16cYwUJzrqJgK3O2gftYgXWz42SzInNMijXk
+Gb+w93KnJ8ueIG27jWqjEFLWVMO7zEK1FmScT9pPpOvQD6rTyTmPT4XZbfiwpMR0
+ba/8JMsHyTk4hOnyV+txpyYGDytKWfTck2bFAQIDAQABAoIBAQCw0ZOyK4sMkyBf
+jyG1EZDdNCvXdOZl5uqOqe58+m36aUnD7D75fAhlW2pyLv36DXKbHUb8zdinFz1c
++EBWWTImmlc7FCfRO0Zc9E/DyLxsqe0JAFJFtIPHiMf/rFpqraYlGYb5hpbjsI2K
+lMpaQW7TpJss9f7NKxjDmfJA5DB6QHxnjA4IkirdrSXJOLyNG5pJXBva9H8fBCjm
+S0nYSu+UuDsg7qhZ0TK5Hyv/3ICbjyby0aNEuurwz30rF/GJbwQTUy/laKntl6Wc
+9RFIa9PPaMty9VQWasU4BxFmIqeQYe1+78XRB/WBxidn2Hq/eZeE/5tmrmj1CLHm
+E2l6vlJBAoGBAP1V2INW6l6QX6eqLtnv5YRYrg1R5wevI2Ooc9hOZ0XBTfLYm6u9
+qmjaH0smmEH2hBAI8Kmk3ixCDAfwXL5XKAWpck66qDM0/ZOm5j8kiBDwsW4hcqgQ
+Jafm6jQEdNvUGkVicfmJweyX4kNp3dA8+XWp5qXYmNCxmbAPScSVKomVAoGBAN4i
+e3s7LXmme0S0/KBvzWBZYqK9LoBXThU03xBV2eDoxA/2UJElRwbf38G6NnDwL1N+
+kUkwQwNmE9Laymalbkgb/q9lOR8kCjS1/Ev/0pQO7qGgX6fzZ5bS2K7uRg0RYfRz
+2XCwO1cBiaNNO/chq7pcSIJZs86wQJY848cPCeq9AoGBAOFbS1ZSq/xhG+Zvemv+
+fsKDjJlmwUjRoH6XrC3AWRfxRGECFUDqYLwTRQE6HPmYzJPjEAspEUZ3nnI1fJsJ
+tx2KRZgJbXTX77c4IdwLqErBgmTAtlkQvB6nSLHrQPUIsjIEx/S+edb4qZtkgqAq
+jZMBB5+ClTYYtumqP+ny87sdAoGAbYbfD8H8CDF4MkZzEcBOqaUpJ0jUdt+VVot9
+ORa7mVPr6FrxGsAgp1kXgPQKB+HF1AtiI44yXKimOZ87kSUcnV2AVIc6hQpGJftd
+bTO0ZuB99R+YSr2PZCSORqKh06uwetHscs3SVHIjpWtdl9r4S6lY7zy/lbf+AJYB
+UZMutpkCgYAcBnZ+2ZIfLJA0oagnTHuXJ4OvfJ3uOCFFGP2KOsyOB3kr/QEJZuvk
+MNvOPv1FSOy7YYnWvSGyeO8CxGzWVv5cw1xJTHn8I0PI9DNzpdAS78JQ/YJhGCA6
+Myo0oru0Nf5wZl4Q1bkBneq9dMOtXmIO0IPgvivCUVOEngfdQ7myNw==
+-----END RSA PRIVATE KEY-----
+-----BEGIN CERTIFICATE-----
+MIIDoDCCAogCAQEwDQYJKoZIhvcNAQELBQAwgZMxCzAJBgNVBAYTAlVTMQswCQYD
+VQQIDAJJTDEOMAwGA1UEBwwFU2F2b3kxDzANBgNVBAoMBllhaG9vITEWMBQGA1UE
+CwwNVHJhZmZpY1NlcnZlcjEQMA4GA1UEAwwHY2VydF9jbjEsMCoGCSqGSIb3DQEJ
+ARYdYnJpYW4ubmVyYWR0QHZlcml6b25tZWRpYS5jb20wIBcNMjAwNjAzMjIzNzAw
+WhgPMjExODEyMjcyMjM3MDBaMIGVMQswCQYDVQQGEwJVUzELMAkGA1UECAwCSUwx
+DjAMBgNVBAcMBVNhdm95MQ8wDQYDVQQKDAZZYWhvbyExFjAUBgNVBAsMDVRyYWZm
+aWNTZXJ2ZXIxEjAQBgNVBAMMCXNlcnZlcl9jbjEsMCoGCSqGSIb3DQEJARYdYnJp
+YW4ubmVyYWR0QHZlcml6b25tZWRpYS5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IB
+DwAwggEKAoIBAQDb0pFa2Ka0XsdF6FjAybyDGnE5wO/BSJfGIsGzAR8faApSCnby
+W+N9t3d4dd7nt1W5fLyz+ae3+N+PwG3ITAgAhuAmcFQYzRXklcnYEKDxDeWioaFu
+JwMlpefCj5k85a7vHkOm8ddf0e4k9RZ4TAi6G047QF9uIO86483b3LsrlPSCQaVH
+GETqOWc03/GD7UgO7XT7whKobGvXpxjBQnOuomArc7aB+1iBdbPjZLMic0yKNeQZ
+v7D3cqcny54gbbuNaqMQUtZUw7vMQrUWZJxP2k+k69APqtPJOY9Phdlt+LCkxHRt
+r/wkywfJOTiE6fJX63GnJgYPK0pZ9NyTZsUBAgMBAAEwDQYJKoZIhvcNAQELBQAD
+ggEBADptfqn5GtjNYqpoXggiIWG5vysYvkUUhih3bwu4aVZeVN+Xr7yyo2DUXzGh
+2OyTtWppLqKmsz1n9Ki3Zz+2dffv7rphKKzy51BDo04HfFPFzkja2U4g2OuZLsnu
+sO2+1Y3Of5S+wE7PoOfpLQKPMVi+cneMQHcluRH7ebLU5WXR8RAYGMcGUnhTOcB2
++bl6lRsdavm+iacAH/baoOVjNZKIqlEpXecsFzGHymOFkshuEO4Yg21lMhgiuaZL
+GaiVYUbVoQ2cPS40z+OHBJTOtDYLGHEwOEstCL/2cnltRIAZItbzdATk1jMEp3vL
+Hfwqku4yO/cku01sjyxQmZai4fA=
+-----END CERTIFICATE-----