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 2019/11/06 00:43:40 UTC

[trafficserver] branch 9.0.x updated: Adding an autest for traffic_dump.

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

zwoop 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 617c6f5  Adding an autest for traffic_dump.
617c6f5 is described below

commit 617c6f5a3587f3fb63f2fab1c11e909d9a487cf9
Author: bneradt <bn...@verizonmedia.com>
AuthorDate: Fri Nov 1 16:22:14 2019 +0000

    Adding an autest for traffic_dump.
    
    (cherry picked from commit 452d60ea7878b202e45b297083641ed3968fc3fb)
---
 plugins/experimental/traffic_dump/traffic_dump.cc  |   2 +-
 tests/Pipfile                                      |   1 +
 .../pluginTest/traffic_dump/gold/200.gold          |  12 +++
 .../pluginTest/traffic_dump/traffic_dump.test.py   | 112 +++++++++++++++++++++
 .../pluginTest/traffic_dump/verify_replay.py       |  96 ++++++++++++++++++
 5 files changed, 222 insertions(+), 1 deletion(-)

diff --git a/plugins/experimental/traffic_dump/traffic_dump.cc b/plugins/experimental/traffic_dump/traffic_dump.cc
index dc73e16..464dd41 100644
--- a/plugins/experimental/traffic_dump/traffic_dump.cc
+++ b/plugins/experimental/traffic_dump/traffic_dump.cc
@@ -602,7 +602,7 @@ TSPluginInit(int argc, const char *argv[])
     TSHttpHookAdd(TS_HTTP_SSN_START_HOOK, ssncont);
     TSHttpHookAdd(TS_HTTP_SSN_CLOSE_HOOK, ssncont);
     TSLifecycleHookAdd(TS_LIFECYCLE_MSG_HOOK, ssncont);
-    TSDebug(PLUGIN_NAME, "Initialized with sample pool size %" PRId64 " bytes and disk limit %" PRId64 "bytes",
+    TSDebug(PLUGIN_NAME, "Initialized with sample pool size %" PRId64 " bytes and disk limit %" PRId64 " bytes",
             sample_pool_size.load(), max_disk_usage.load());
   }
 
diff --git a/tests/Pipfile b/tests/Pipfile
index f8a6bcc..aa4a6e8 100644
--- a/tests/Pipfile
+++ b/tests/Pipfile
@@ -31,6 +31,7 @@ requests = "*"
 gunicorn = "*"
 httpbin = "*"
 microserver = ">=1.0.4"
+jsonschema = "*"
 
 [requires]
 python_version = "3"
diff --git a/tests/gold_tests/pluginTest/traffic_dump/gold/200.gold b/tests/gold_tests/pluginTest/traffic_dump/gold/200.gold
new file mode 100644
index 0000000..71aa5d5
--- /dev/null
+++ b/tests/gold_tests/pluginTest/traffic_dump/gold/200.gold
@@ -0,0 +1,12 @@
+``
+> GET /`` HTTP/1.1
+> Host: www.example.com``
+> User-Agent: curl/``
+> Accept: */*
+``
+< HTTP/1.1 200 OK
+< Content-Length: 0
+< Date: ``
+< Age: ``
+< Server: ATS/``
+``
diff --git a/tests/gold_tests/pluginTest/traffic_dump/traffic_dump.test.py b/tests/gold_tests/pluginTest/traffic_dump/traffic_dump.test.py
new file mode 100644
index 0000000..1b4be84
--- /dev/null
+++ b/tests/gold_tests/pluginTest/traffic_dump/traffic_dump.test.py
@@ -0,0 +1,112 @@
+"""
+Verify traffic_dump functionality.
+"""
+#  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
+Test.Summary = '''
+Verify traffic_dump functionality.
+'''
+
+Test.SkipUnless(
+    Condition.PluginExists('traffic_dump.so'),
+)
+
+# Configure the origin server.
+server = Test.MakeOriginServer("server")
+
+request_header = {"headers": "GET / HTTP/1.1\r\nHost: www.example.com\r\nContent-Length: 0\r\n\r\n",
+                  "timestamp": "1469733493.993", "body": ""}
+response_header = {"headers": "HTTP/1.1 200 OK\r\nConnection: close\r\nContent-Length: 0\r\n\r\n",
+                   "timestamp": "1469733493.993", "body": ""}
+server.addResponse("sessionfile.log", request_header, response_header)
+
+# Define ATS and configure
+ts = Test.MakeATSProcess("ts")
+replay_dir = os.path.join(ts.RunDirectory, "ts", "log")
+ts.Disk.records_config.update({
+    'proxy.config.diags.debug.enabled': 1,
+    'proxy.config.diags.debug.tags': 'traffic_dump',
+})
+ts.Disk.remap_config.AddLine(
+    'map / http://127.0.0.1:{0}'.format(server.Variables.Port)
+)
+# Configure traffic_dump.
+ts.Disk.plugin_config.AddLine(
+    'traffic_dump.so --logdir {0} --sample 1 --limit 1000000000'.format(replay_dir)
+)
+
+# Set up trafficserver expectations.
+ts.Disk.diags_log.Content = Testers.ContainsExpression(
+        "loading plugin.*traffic_dump.so",
+        "Verify the traffic_dump plugin got loaded.")
+ts.Streams.stderr = Testers.ContainsExpression(
+        "Initialized with log directory: {0}".format(replay_dir),
+        "Verify traffic_dump initialized with the configured directory.")
+ts.Streams.stderr += Testers.ContainsExpression(
+        "Initialized with sample pool size 1 bytes and disk limit 1000000000 bytes",
+        "Verify traffic_dump initialized with the configured disk limit.")
+
+# Set up the json replay file expectations.
+replay_file_session_1 = os.path.join(replay_dir, "127", "0000000000000000")
+ts.Disk.File(replay_file_session_1, exists=True)
+replay_file_session_2 = os.path.join(replay_dir, "127", "0000000000000001")
+ts.Disk.File(replay_file_session_2, exists=True)
+
+# Execute the first transaction.
+tr = Test.AddTestRun("First transaction")
+
+tr.Processes.Default.StartBefore(server, ready=When.PortOpen(server.Variables.Port))
+tr.Processes.Default.StartBefore(Test.Processes.ts)
+tr.Processes.Default.Command = 'curl http://127.0.0.1:{0} -H\'Host: www.example.com\' --verbose'.format(
+    ts.Variables.port)
+tr.Processes.Default.ReturnCode = 0
+tr.Processes.Default.Streams.stderr = "gold/200.gold"
+tr.StillRunningAfter = server
+tr.StillRunningAfter = ts
+
+# Execute the second transaction.
+tr = Test.AddTestRun("Second transaction")
+tr.Processes.Default.Command = 'curl http://127.0.0.1:{0} -H\'Host: www.example.com\' --verbose'.format(
+    ts.Variables.port)
+tr.Processes.Default.ReturnCode = 0
+tr.Processes.Default.Streams.stderr = "gold/200.gold"
+tr.StillRunningAfter = server
+tr.StillRunningAfter = ts
+
+# Verify the properties of the replay file for the first transaction.
+tr = Test.AddTestRun("Verify the json content of the first session")
+verify_replay = "verify_replay.py"
+tr.Setup.CopyAs(verify_replay, Test.RunDirectory)
+tr.Processes.Default.Command = "python3 {0} {1} {2}".format(
+        verify_replay,
+        os.path.join(Test.Variables.AtsTestToolsDir, 'lib', 'replay_schema.json'),
+        replay_file_session_1)
+tr.Processes.Default.ReturnCode = 0
+tr.StillRunningAfter = server
+tr.StillRunningAfter = ts
+
+# Verify the properties of the replay file for the second transaction.
+tr = Test.AddTestRun("Verify the json content of the second session")
+tr.Setup.CopyAs(verify_replay, Test.RunDirectory)
+tr.Processes.Default.Command = "python3 {0} {1} {2}".format(
+        verify_replay,
+        os.path.join(Test.Variables.AtsTestToolsDir, 'lib', 'replay_schema.json'),
+        replay_file_session_2)
+tr.Processes.Default.ReturnCode = 0
+tr.StillRunningAfter = server
+tr.StillRunningAfter = ts
diff --git a/tests/gold_tests/pluginTest/traffic_dump/verify_replay.py b/tests/gold_tests/pluginTest/traffic_dump/verify_replay.py
new file mode 100644
index 0000000..5b5738a
--- /dev/null
+++ b/tests/gold_tests/pluginTest/traffic_dump/verify_replay.py
@@ -0,0 +1,96 @@
+"""
+Verify that a given JSON replay file fulfills basic expectations.
+"""
+#  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 argparse
+import json
+import jsonschema
+import sys
+
+
+def validate_json(schema_json, replay_json):
+    """
+    Validate the replay file against the provided schema.
+    """
+    try:
+        jsonschema.validate(instance=replay_json, schema=schema_json)
+    except jsonschema.ValidationError:
+        print("The replay file does not validate against the schema.")
+        return False
+    else:
+        return True
+
+
+def verify_there_was_a_transaction(replay_json):
+    """
+    Verify that the replay file has a sensible looking transaction.
+    """
+    try:
+        transactions = replay_json['sessions'][0]['transactions']
+    except KeyError:
+        print("The replay file did not have transactions in it.")
+        return False
+
+    if len(transactions) < 1:
+        print("There are no transactions in the replay file.")
+        return False
+    transaction = transactions[0]
+    if not ('client-request' in transaction and 'server-response' in transaction):
+        print("There was not request and response in the transaction of the replay file.")
+        return False
+
+    return True
+
+
+def parse_args():
+    parser = argparse.ArgumentParser()
+    parser.add_argument("schema_file",
+                        type=argparse.FileType('r'),
+                        help="The schema in which to interpret validate the replay file.")
+    parser.add_argument("replay_file",
+                        type=argparse.FileType('r'),
+                        help="The replay file to validate.")
+    return parser.parse_args()
+
+
+def main():
+    args = parse_args()
+
+    schema_json = json.load(args.schema_file)
+    replay_json = json.load(args.replay_file)
+
+    if not validate_json(schema_json, replay_json):
+        return 1
+
+    # Verifying that there is a transaction in the replay file may seem
+    # unnecessary since the replay file validated against the schema. But a JSON
+    # file that doesn't have conflicting entry names will pass the schema. For
+    # instance, this passes against our replay schema:
+    #
+    # {"name": "Bob", "languages": ["English", "French"]}
+    #
+    # Thus we do the following sanity check to make sure that the replay file
+    # appears to have some transaction in it.
+    if not verify_there_was_a_transaction(replay_json):
+        return 1
+
+    return 0
+
+
+if __name__ == '__main__':
+    sys.exit(main())