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

dmeden pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/trafficserver.git


The following commit(s) were added to refs/heads/master by this push:
     new 425939c6d0 traffic_ctl - Implement `server status` command option. 
(#12183)
425939c6d0 is described below

commit 425939c6d0d2ee9eca89a2fe5278d8fd5be539a0
Author: Damian Meden <[email protected]>
AuthorDate: Tue Apr 22 10:40:12 2025 +0200

    traffic_ctl - Implement `server status` command option. (#12183)
    
    * traffic_ctl - Implement server status command option.
    
    With the removal of traffic_manager we lost this command option, so now
    this change  makes ATS to respond the rpc call with some basic 
`TSSystemState`
    Information, like intimidation status, draining status, etc.
    The output is a simple json output.
    Command option is read only, no change is done in the internal ATS state.
    
    Example:
    
    $ traffic_ctl server status | jq
    {
        "initialized_done": "true",
        "is_ssl_handshaking_stopped": "false",
        "is_draining": "false",
        "is_event_system_shut_down": "false"
    }
    
    This also includes some autests to validate the output. Changes to
    existing traffic_ctl autest machinery is made to make it simpler to
    extend and add more tests.
    
    * Fix docs
---
 doc/appendices/command-line/traffic_ctl.en.rst     |  19 ++-
 include/mgmt/rpc/handlers/server/Server.h          |   2 +
 src/mgmt/rpc/handlers/server/Server.cc             |  23 +++
 src/traffic_ctl/CtrlCommands.cc                    |  10 ++
 src/traffic_ctl/CtrlCommands.h                     |   3 +
 src/traffic_ctl/CtrlPrinters.cc                    |   7 +-
 src/traffic_ctl/CtrlPrinters.h                     |   9 ++
 src/traffic_ctl/jsonrpc/CtrlRPCRequests.h          |   9 ++
 src/traffic_ctl/traffic_ctl.cc                     |  12 +-
 src/traffic_server/RpcAdminPubHandlers.cc          |   6 +-
 .../traffic_ctl/traffic_ctl_config_output.test.py  | 146 +-----------------
 .../traffic_ctl/traffic_ctl_server_output.test.py  |  45 ++++++
 ...ig_output.test.py => traffic_ctl_test_utils.py} | 169 +++++++++++----------
 13 files changed, 223 insertions(+), 237 deletions(-)

diff --git a/doc/appendices/command-line/traffic_ctl.en.rst 
b/doc/appendices/command-line/traffic_ctl.en.rst
index 8eaee48e6d..c6009a4964 100644
--- a/doc/appendices/command-line/traffic_ctl.en.rst
+++ b/doc/appendices/command-line/traffic_ctl.en.rst
@@ -46,7 +46,7 @@ of subcommands that control different aspects of Traffic 
Server:
 :program:`traffic_ctl metric`
    Manipulate performance and status metrics
 :program:`traffic_ctl server`
-   Stop, restart and examine the server
+   Examine the server
 :program:`traffic_ctl storage`
    Manipulate cache storage
 :program:`traffic_ctl plugin`
@@ -385,10 +385,25 @@ traffic_ctl server
 
    Drop the number of active client connections.
 
+
+.. _traffic-control-command-server-status:
+
 .. program:: traffic_ctl server
 .. option:: status
 
-   Option not yet available
+   Display basic |TS| internal running information.
+
+   Example:
+
+   .. code-block:: bash
+
+      $ traffic_ctl server status | jq
+      {
+         "initialized_done": "true",
+         "is_ssl_handshaking_stopped": "false",
+         "is_draining": "false",
+         "is_event_system_shut_down": "false"
+      }
 
 .. _traffic-control-command-server-debug:
 
diff --git a/include/mgmt/rpc/handlers/server/Server.h 
b/include/mgmt/rpc/handlers/server/Server.h
index 2806ec4155..face7053f4 100644
--- a/include/mgmt/rpc/handlers/server/Server.h
+++ b/include/mgmt/rpc/handlers/server/Server.h
@@ -27,4 +27,6 @@ namespace rpc::handlers::server
 swoc::Rv<YAML::Node> server_start_drain(std::string_view const &id, YAML::Node 
const &params);
 swoc::Rv<YAML::Node> server_stop_drain(std::string_view const &id, YAML::Node 
const &);
 void                 server_shutdown(YAML::Node const &);
+swoc::Rv<YAML::Node> get_server_status(std::string_view const &id, YAML::Node 
const &);
+
 } // namespace rpc::handlers::server
diff --git a/src/mgmt/rpc/handlers/server/Server.cc 
b/src/mgmt/rpc/handlers/server/Server.cc
index 3bccc8ef0b..c032e7a7ff 100644
--- a/src/mgmt/rpc/handlers/server/Server.cc
+++ b/src/mgmt/rpc/handlers/server/Server.cc
@@ -127,4 +127,27 @@ server_shutdown(YAML::Node const &)
 {
   sync_cache_dir_on_shutdown();
 }
+
+swoc::Rv<YAML::Node>
+get_server_status(std::string_view const & /* params ATS_UNUSED */, YAML::Node 
const & /* params ATS_UNUSED */)
+{
+  swoc::Rv<YAML::Node> resp;
+  try {
+    auto bts = [](bool val) -> std::string { return val ? "true" : "false"; };
+
+    YAML::Node data;
+    data["initialized_done"]           = 
bts(!TSSystemState::is_initializing());
+    data["is_ssl_handshaking_stopped"] = 
bts(TSSystemState::is_ssl_handshaking_stopped());
+    data["is_draining"]                = bts(TSSystemState::is_draining());
+    data["is_event_system_shut_down"]  = 
bts(TSSystemState::is_event_system_shut_down());
+
+    resp.result()["data"] = data;
+
+  } catch (std::exception const &ex) {
+    resp.errata()
+      .assign(std::error_code{errors::Codes::SERVER})
+      .note("Error found when calling get_server_status API: {}", ex.what());
+  }
+  return resp;
+}
 } // namespace rpc::handlers::server
diff --git a/src/traffic_ctl/CtrlCommands.cc b/src/traffic_ctl/CtrlCommands.cc
index ae290c463e..7a94ad067c 100644
--- a/src/traffic_ctl/CtrlCommands.cc
+++ b/src/traffic_ctl/CtrlCommands.cc
@@ -562,6 +562,9 @@ ServerCommand::ServerCommand(ts::Arguments *args) : 
CtrlCommand(args)
   } else if (get_parsed_arguments()->get(DEBUG_STR)) {
     _printer      = std::make_unique<GenericPrinter>(printOpts);
     _invoked_func = [&]() { server_debug(); };
+  } else if (get_parsed_arguments()->get(STATUS_STR)) {
+    _printer      = std::make_unique<ServerStatusPrinter>(printOpts);
+    _invoked_func = [&]() { server_status(); };
   }
 }
 
@@ -609,6 +612,13 @@ ServerCommand::server_debug()
   }
 }
 
+void
+ServerCommand::server_status()
+{
+  shared::rpc::JSONRPCResponse response = invoke_rpc(GetServerStatusRequest{});
+  _printer->write_output(response);
+}
+
 // 
//------------------------------------------------------------------------------------------------------------------------------------
 StorageCommand::StorageCommand(ts::Arguments *args) : CtrlCommand(args)
 {
diff --git a/src/traffic_ctl/CtrlCommands.h b/src/traffic_ctl/CtrlCommands.h
index 3da9222291..e20d70d8dd 100644
--- a/src/traffic_ctl/CtrlCommands.h
+++ b/src/traffic_ctl/CtrlCommands.h
@@ -220,8 +220,11 @@ private:
   static inline const std::string TAGS_STR{"tags"};
   static inline const std::string CLIENT_IP_STR{"client_ip"};
 
+  static inline const std::string STATUS_STR{"status"};
+
   void server_drain();
   void server_debug();
+  void server_status();
 };
 //
 // 
-----------------------------------------------------------------------------------------------------------------------------------
diff --git a/src/traffic_ctl/CtrlPrinters.cc b/src/traffic_ctl/CtrlPrinters.cc
index 1458cc8a9f..caf0f09b82 100644
--- a/src/traffic_ctl/CtrlPrinters.cc
+++ b/src/traffic_ctl/CtrlPrinters.cc
@@ -359,4 +359,9 @@ RPCAPIPrinter::write_output(YAML::Node const &result)
   }
 }
 
//------------------------------------------------------------------------------------------------------------------------------------
-//---------------------------------------------------------------------------------------------------------------------------------
+void
+ServerStatusPrinter::write_output(YAML::Node const &result)
+{
+  write_output_json(result["data"] ? result["data"] : result);
+}
+//-------------------------------------------------------------------------------------------------------------------------------------
diff --git a/src/traffic_ctl/CtrlPrinters.h b/src/traffic_ctl/CtrlPrinters.h
index d0e8a4bbd8..844a364d26 100644
--- a/src/traffic_ctl/CtrlPrinters.h
+++ b/src/traffic_ctl/CtrlPrinters.h
@@ -283,3 +283,12 @@ public:
   RPCAPIPrinter(BasePrinter::Options opt) : BasePrinter(opt) {}
 };
 
//------------------------------------------------------------------------------------------------------------------------------------
+//------------------------------------------------------------------------------------------------------------------------------------
+class ServerStatusPrinter : public BasePrinter
+{
+  void write_output(YAML::Node const &result) override;
+
+public:
+  ServerStatusPrinter(BasePrinter::Options opt) : BasePrinter(opt) {}
+};
+//------------------------------------------------------------------------------------------------------------------------------------
diff --git a/src/traffic_ctl/jsonrpc/CtrlRPCRequests.h 
b/src/traffic_ctl/jsonrpc/CtrlRPCRequests.h
index 7ca103d036..862ecc68b3 100644
--- a/src/traffic_ctl/jsonrpc/CtrlRPCRequests.h
+++ b/src/traffic_ctl/jsonrpc/CtrlRPCRequests.h
@@ -161,6 +161,15 @@ struct ServerStopDrainRequest : shared::rpc::ClientRequest 
{
   }
 };
 
//------------------------------------------------------------------------------------------------------------------------------------
+struct GetServerStatusRequest : shared::rpc::ClientRequest {
+  using super = ClientRequest;
+  std::string
+  get_method() const override
+  {
+    return "get_server_status";
+  }
+};
+//------------------------------------------------------------------------------------------------------------------------------------
 struct SetStorageDeviceOfflineRequest : shared::rpc::ClientRequest {
   using super = shared::rpc::ClientRequest;
   struct Params {
diff --git a/src/traffic_ctl/traffic_ctl.cc b/src/traffic_ctl/traffic_ctl.cc
index d760681e1e..37299f39ad 100644
--- a/src/traffic_ctl/traffic_ctl.cc
+++ b/src/traffic_ctl/traffic_ctl.cc
@@ -169,18 +169,8 @@ main([[maybe_unused]] int argc, const char **argv)
   // server commands
   server_command.add_command("backtrace", "Show a full stack trace of the 
traffic_server process",
                              [&]() { CtrlUnimplementedCommand("backtrace"); });
-  server_command.add_command("restart", "Restart Traffic Server", [&]() { 
CtrlUnimplementedCommand("restart"); })
-    .add_example_usage("traffic_ctl server restart [OPTIONS]")
-    .add_option("--drain", "", "Wait for client connections to drain before 
restarting");
-  server_command.add_command("start", "Start the proxy", [&]() { 
CtrlUnimplementedCommand("start"); })
-    .add_example_usage("traffic_ctl server start [OPTIONS]")
-    .add_option("--clear-cache", "", "Clear the disk cache on startup")
-    .add_option("--clear-hostdb", "", "Clear the DNS cache on startup");
-  server_command.add_command("status", "Show the proxy status", [&]() { 
CtrlUnimplementedCommand("status"); })
+  server_command.add_command("status", "Show the proxy status", [&]() { 
command->execute(); })
     .add_example_usage("traffic_ctl server status");
-  server_command.add_command("stop", "Stop the proxy", [&]() { 
CtrlUnimplementedCommand("stop"); })
-    .add_example_usage("traffic_ctl server stop [OPTIONS]")
-    .add_option("--drain", "", "Wait for client connections to drain before 
stopping");
   server_command.add_command("drain", "Drain the requests", [&]() { 
command->execute(); })
     .add_example_usage("traffic_ctl server drain [OPTIONS]")
     .add_option("--no-new-connection", "-N", "Wait for new connections down to 
threshold before starting draining")
diff --git a/src/traffic_server/RpcAdminPubHandlers.cc 
b/src/traffic_server/RpcAdminPubHandlers.cc
index 99a2b20120..7e6e0fdff7 100644
--- a/src/traffic_server/RpcAdminPubHandlers.cc
+++ b/src/traffic_server/RpcAdminPubHandlers.cc
@@ -55,10 +55,8 @@ register_admin_jsonrpc_handlers()
                           {{rpc::RESTRICTED_API}});
   rpc::add_method_handler("admin_server_stop_drain", &server_stop_drain, 
&core_ats_rpc_service_provider_handle,
                           {{rpc::RESTRICTED_API}});
-  rpc::add_notification_handler("admin_server_shutdown", &server_shutdown, 
&core_ats_rpc_service_provider_handle,
-                                {{rpc::RESTRICTED_API}});
-  rpc::add_notification_handler("admin_server_restart", &server_shutdown, 
&core_ats_rpc_service_provider_handle,
-                                {{rpc::RESTRICTED_API}});
+  rpc::add_method_handler("get_server_status", &get_server_status, 
&core_ats_rpc_service_provider_handle,
+                          {{rpc::NON_RESTRICTED_API}});
 
   // storage
   using namespace rpc::handlers::storage;
diff --git a/tests/gold_tests/traffic_ctl/traffic_ctl_config_output.test.py 
b/tests/gold_tests/traffic_ctl/traffic_ctl_config_output.test.py
index cdfe65ab72..d4643527db 100644
--- a/tests/gold_tests/traffic_ctl/traffic_ctl_config_output.test.py
+++ b/tests/gold_tests/traffic_ctl/traffic_ctl_config_output.test.py
@@ -13,8 +13,13 @@
 #  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 sys
 import os
+
+# To include util classes
+sys.path.insert(0, f'{Test.TestDirectory}')
+
+from traffic_ctl_test_utils import Make_traffic_ctl
 # import ruamel.yaml Uncomment only when GoldFilePathFor is used.
 
 Test.Summary = '''
@@ -23,143 +28,6 @@ Test traffic_ctl config output responses.
 
 Test.ContinueOnFail = True
 
-TestNumber = 0
-
-
-def IncTestNumber():
-    global TestNumber
-    TestNumber = TestNumber + 1
-
-
-# This function can(eventually) be used to have a single yaml file and read 
nodes from it.
-# The idea would be to avoid having multiple gold files with yaml content.
-# The only issue would be the comments, this is because how the yaml lib reads 
yaml,
-# comments  aren't rendered in the same way as traffic_ctl throws it, it 
should only
-# be used if no comments need to be compared.
-#
-# def GoldFilePathFor(node:str, main_file="gold/test_gold_file.yaml"):
-#     if node == "":
-#         raise Exception("node should not be empty")
-
-#     yaml = ruamel.yaml.YAML()
-#     yaml.indent(sequence=4, offset=2)
-#     with open(os.path.join(Test.TestDirectory, main_file), 'r') as f:
-#         content = yaml.load(f)
-
-#     node_data = content[node]
-#     data_dirname = 'generated_gold_files'
-#     data_path = os.path.join(Test.TestDirectory, data_dirname)
-#     os.makedirs(data_path, exist_ok=True)
-#     gold_filepath = os.path.join(data_path, f'test_{TestNumber}.gold')
-#     with open(os.path.join(data_path, f'test_{TestNumber}.gold'), 'w') as 
gold_file:
-#         yaml.dump(node_data, gold_file)
-
-#     return gold_filepath
-
-
-def MakeGoldFileWithText(content, add_new_line=True):
-    data_path = os.path.join(Test.TestDirectory, "gold")
-    os.makedirs(data_path, exist_ok=True)
-    gold_filepath = os.path.join(data_path, f'test_{TestNumber}.gold')
-    with open(gold_filepath, 'w') as gold_file:
-        if add_new_line:
-            content = f"{content}\n"
-        gold_file.write(content)
-
-    return gold_filepath
-
-
-class Config():
-    """
-        Handy class to map traffic_ctl config options.
-    """
-
-    def __init__(self, tr):
-        self._cmd = "traffic_ctl config "
-        self._tr = tr
-
-    def diff(self):
-        self._cmd = f'{self._cmd} diff'
-        return self
-
-    def get(self, value):
-        self._cmd = f'{self._cmd} get {value}'
-        return self
-
-    def match(self, value):
-        self._cmd = f'{self._cmd}  match {value}'
-        return self
-
-    def describe(self, value):
-        self._cmd = f'{self._cmd}  describe {value}'
-        return self
-
-    def as_records(self):
-        self._cmd = f'{self._cmd} --records'
-        return self
-
-    def with_default(self):
-        self._cmd = f'{self._cmd}  --default'
-        return self
-
-    def __finish(self):
-        """
-            Sets the command to the test. Make sure this gets called after
-            validation is set. Without this call the test will fail.
-        """
-        self._tr.Processes.Default.Command = self._cmd
-
-    def validate_with_goldfile(self, file: str):
-        self._tr.Processes.Default.Streams.stdout = os.path.join("gold", file)
-        self.__finish()
-
-    def validate_with_text(self, text: str):
-        self._tr.Processes.Default.Streams.stdout = MakeGoldFileWithText(text)
-        self.__finish()
-
-
-class TrafficCtl(Config):
-    """
-        Single TS instance with multiple tests.
-        Every time a config() is called, a new test is created.
-    """
-
-    def __init__(self, records_yaml=None):
-        self._current_test_number = TestNumber
-
-        self._ts = Test.MakeATSProcess(f"ts_{TestNumber}")
-        if records_yaml != None:
-            self._ts.Disk.records_config.update(records_yaml)
-        self._tests = []
-
-    def __get_index(self):
-        return self._current_test_number
-
-    def add_test(self):
-
-        tr = Test.AddTestRun(f"test {TestNumber}")
-        if TestNumber == 0:
-            tr.Processes.Default.StartBefore(self._ts)
-        IncTestNumber()
-
-        tr.Processes.Default.Env = self._ts.Env
-        tr.DelayStart = 3
-        tr.Processes.Default.ReturnCode = 0
-        tr.StillRunningAfter = self._ts
-
-        self._tests.insert(self.__get_index(), tr)
-        return self
-
-    def config(self):
-        self.add_test()
-        return Config(self._tests[self.__get_index()])
-
-
-def Make_traffic_ctl(records_yaml):
-    tctl = TrafficCtl(records_yaml)
-    return tctl
-
-
 records_yaml = '''
     udp:
       threads: 1
@@ -170,7 +38,7 @@ records_yaml = '''
         throttling_interval_msec: 0
     '''
 
-traffic_ctl = Make_traffic_ctl(records_yaml)
+traffic_ctl = Make_traffic_ctl(Test, records_yaml)
 
 ##### CONFIG GET
 
diff --git a/tests/gold_tests/traffic_ctl/traffic_ctl_server_output.test.py 
b/tests/gold_tests/traffic_ctl/traffic_ctl_server_output.test.py
new file mode 100644
index 0000000000..747eb2a97f
--- /dev/null
+++ b/tests/gold_tests/traffic_ctl/traffic_ctl_server_output.test.py
@@ -0,0 +1,45 @@
+#  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 sys
+import os
+
+# To include util classes
+sys.path.insert(0, f'{Test.TestDirectory}')
+
+from traffic_ctl_test_utils import Make_traffic_ctl
+
+Test.Summary = '''
+Test traffic_ctl different commands.
+'''
+
+Test.ContinueOnFail = True
+
+Test.Summary = 'Basic test for traffic_ctl server command features.'
+
+traffic_ctl = Make_traffic_ctl(Test)
+######
+# traffic_ctl server status
+traffic_ctl.server().status().validate_with_text(
+    '{"initialized_done": "true", "is_ssl_handshaking_stopped": "false", 
"is_draining": "false", "is_event_system_shut_down": "false"}'
+)
+# Drain ats so we can check the output.
+traffic_ctl.server().drain().exec()
+
+# After the drain, server status should reflect this change.
+traffic_ctl.server().status().validate_with_text(
+    '{"initialized_done": "true", "is_ssl_handshaking_stopped": "false", 
"is_draining": "true", "is_event_system_shut_down": "false"}'
+)
diff --git a/tests/gold_tests/traffic_ctl/traffic_ctl_config_output.test.py 
b/tests/gold_tests/traffic_ctl/traffic_ctl_test_utils.py
similarity index 60%
copy from tests/gold_tests/traffic_ctl/traffic_ctl_config_output.test.py
copy to tests/gold_tests/traffic_ctl/traffic_ctl_test_utils.py
index cdfe65ab72..c8a2d57576 100644
--- a/tests/gold_tests/traffic_ctl/traffic_ctl_config_output.test.py
+++ b/tests/gold_tests/traffic_ctl/traffic_ctl_test_utils.py
@@ -15,21 +15,6 @@
 #  limitations under the License.
 
 import os
-# import ruamel.yaml Uncomment only when GoldFilePathFor is used.
-
-Test.Summary = '''
-Test traffic_ctl config output responses.
-'''
-
-Test.ContinueOnFail = True
-
-TestNumber = 0
-
-
-def IncTestNumber():
-    global TestNumber
-    TestNumber = TestNumber + 1
-
 
 # This function can(eventually) be used to have a single yaml file and read 
nodes from it.
 # The idea would be to avoid having multiple gold files with yaml content.
@@ -57,10 +42,10 @@ def IncTestNumber():
 #     return gold_filepath
 
 
-def MakeGoldFileWithText(content, add_new_line=True):
-    data_path = os.path.join(Test.TestDirectory, "gold")
+def MakeGoldFileWithText(content, dir, test_number, add_new_line=True):
+    data_path = os.path.join(dir, "gold")
     os.makedirs(data_path, exist_ok=True)
-    gold_filepath = os.path.join(data_path, f'test_{TestNumber}.gold')
+    gold_filepath = os.path.join(data_path, f'test_{test_number}.gold')
     with open(gold_filepath, 'w') as gold_file:
         if add_new_line:
             content = f"{content}\n"
@@ -74,9 +59,11 @@ class Config():
         Handy class to map traffic_ctl config options.
     """
 
-    def __init__(self, tr):
+    def __init__(self, dir, tr, tn):
         self._cmd = "traffic_ctl config "
         self._tr = tr
+        self._dir = dir
+        self._tn = tn
 
     def diff(self):
         self._cmd = f'{self._cmd} diff'
@@ -114,20 +101,88 @@ class Config():
         self.__finish()
 
     def validate_with_text(self, text: str):
-        self._tr.Processes.Default.Streams.stdout = MakeGoldFileWithText(text)
+        self._tr.Processes.Default.Streams.stdout = MakeGoldFileWithText(text, 
self._dir, self._tn)
         self.__finish()
 
 
-class TrafficCtl(Config):
+class Server():
+    """
+        Handy class to map traffic_ctl server options.
+    """
+
+    def __init__(self, dir, tr, tn):
+        self._cmd = "traffic_ctl server "
+        self._tr = tr
+        self._dir = dir
+        self._tn = tn
+
+    def status(self):
+        self._cmd = f'{self._cmd}  status '
+        return self
+
+    def drain(self, undo=False):
+        self._cmd = f'{self._cmd}  drain '
+        if undo:
+            self._cmd = f'{self._cmd} --undo'
+        return self
+
+    def as_json(self):
+        self._cmd = f'{self._cmd} -f json'
+        return self
+
+    """
+    If you need to just run the command with no validation, this is ok in the 
context of a test, but not to be
+    used in isolation(as to run traffic_ctl commands)
+    """
+
+    def exec(self):
+        self.__finish()
+
+    def __finish(self):
+        """
+            Sets the command to the test. Make sure this gets called after
+            validation is set. Without this call the test will fail.
+        """
+        self._tr.Processes.Default.Command = self._cmd
+
+    def validate_with_text(self, text: str):
+        self._tr.Processes.Default.Streams.stdout = MakeGoldFileWithText(text, 
self._dir, self._tn)
+        self.__finish()
+
+
+'''
+
+Handy wrapper around traffic_ctl, ATS and the autest output validation 
mechanism.
+The Idea is to use this as a way to validate traffic_ctl output and not to 
execute traffic_ctl command(though it can and is
+recommended in the context of  test)
+
+Example for a single test.
+
+# create the traffic_ctl wrapper.
+traffic_ctl = Make_traffic_ctl(Test, records_yaml)
+
+## if the output is simple, then you can just
+traffic_ctl.config().get("proxy.config.diags.debug.enabled").validate_with_text("proxy.config.diags.debug.enabled:
 1")
+
+# if the poutput is a bit complex, then you can just set your own gold file.
+traffic_ctl.config().get("proxy.config.diags.debug.tags").as_records().validate_with_goldfile("your_gold_file.gold")
+
+
+'''
+
+
+class TrafficCtl(Config, Server):
     """
         Single TS instance with multiple tests.
         Every time a config() is called, a new test is created.
     """
 
-    def __init__(self, records_yaml=None):
-        self._current_test_number = TestNumber
+    def __init__(self, test, records_yaml=None):
+        self._testNumber = 0
+        self._current_test_number = self._testNumber
 
-        self._ts = Test.MakeATSProcess(f"ts_{TestNumber}")
+        self._Test = test
+        self._ts = self._Test.MakeATSProcess(f"ts_{self._testNumber}")
         if records_yaml != None:
             self._ts.Disk.records_config.update(records_yaml)
         self._tests = []
@@ -137,10 +192,10 @@ class TrafficCtl(Config):
 
     def add_test(self):
 
-        tr = Test.AddTestRun(f"test {TestNumber}")
-        if TestNumber == 0:
+        tr = self._Test.AddTestRun(f"test {self._testNumber}")
+        if self._testNumber == 0:
             tr.Processes.Default.StartBefore(self._ts)
-        IncTestNumber()
+        self._testNumber = self._testNumber + 1
 
         tr.Processes.Default.Env = self._ts.Env
         tr.DelayStart = 3
@@ -152,59 +207,13 @@ class TrafficCtl(Config):
 
     def config(self):
         self.add_test()
-        return Config(self._tests[self.__get_index()])
-
-
-def Make_traffic_ctl(records_yaml):
-    tctl = TrafficCtl(records_yaml)
-    return tctl
-
+        return Config(self._Test.TestDirectory, 
self._tests[self.__get_index()], self._testNumber)
 
-records_yaml = '''
-    udp:
-      threads: 1
-    diags:
-      debug:
-        enabled: 1
-        tags: rpc
-        throttling_interval_msec: 0
-    '''
-
-traffic_ctl = Make_traffic_ctl(records_yaml)
-
-##### CONFIG GET
-
-# YAML output
-traffic_ctl.config().get("proxy.config.diags.debug.tags").as_records().validate_with_goldfile("t1_yaml.gold")
-# Default output
-traffic_ctl.config().get("proxy.config.diags.debug.enabled").validate_with_text("proxy.config.diags.debug.enabled:
 1")
-# Default output with default.
-traffic_ctl.config().get("proxy.config.diags.debug.tags").with_default() \
-    .validate_with_text("proxy.config.diags.debug.tags: rpc # default 
http|dns")
-
-# Now same output test but with defaults, traffic_ctl supports adding default 
value
-# when using --records.
-traffic_ctl.config().get("proxy.config.diags.debug.tags").as_records().with_default().validate_with_goldfile("t2_yaml.gold")
-traffic_ctl.config().get(
-    "proxy.config.diags.debug.tags proxy.config.diags.debug.enabled 
proxy.config.diags.debug.throttling_interval_msec").as_records(
-    ).with_default().validate_with_goldfile("t3_yaml.gold")
-
-##### CONFIG MATCH
-traffic_ctl.config().match("threads").with_default().validate_with_goldfile("match.gold")
-
-# The idea is to check the traffic_ctl yaml emitter when a value starts with 
the
-# same prefix of a node like:
-# diags:
-#    logfile:
-#    logfile_perm: rw-r--r--
-#
-# traffic_ctl have a special logic to deal with cases like this, so better 
test it.
-traffic_ctl.config().match("diags.logfile").as_records().validate_with_goldfile("t4_yaml.gold")
+    def server(self):
+        self.add_test()
+        return Server(self._Test.TestDirectory, 
self._tests[self.__get_index()], self._testNumber)
 
-##### CONFIG DIFF
-traffic_ctl.config().diff().validate_with_goldfile("diff.gold")
-traffic_ctl.config().diff().as_records().validate_with_goldfile("diff_yaml.gold")
 
-##### CONFIG DESCRIBE
-# don't really care about values, but just output and that the command 
actually went through
-traffic_ctl.config().describe("proxy.config.http.server_ports").validate_with_goldfile("describe.gold")
+def Make_traffic_ctl(test, records_yaml=None):
+    tctl = TrafficCtl(test, records_yaml)
+    return tctl

Reply via email to