Skip to content

Commit 1f9186e

Browse files
authored
Test: traffic_ctl_output_test*: Add validate functions for specific JSON fields validation (#12627)
* Test: Add validate_json_contains for traffic_ctl output JSON validation Add validate_json_contains() to validate specific JSON fields without exact output matches. Updated traffic_ctl_server_output.test.py to use the new method for server status checks, making tests more maintainable. Also re-order some functions.
1 parent 65afcf0 commit 1f9186e

File tree

2 files changed

+56
-25
lines changed

2 files changed

+56
-25
lines changed

tests/gold_tests/traffic_ctl/traffic_ctl_server_output.test.py

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -40,16 +40,13 @@
4040
traffic_ctl = Make_traffic_ctl(Test, records_yaml)
4141
######
4242
# traffic_ctl server status
43-
traffic_ctl.server().status().validate_with_text(
44-
'{"initialized_done": "true", "is_ssl_handshaking_stopped": "false", "is_draining": "false", "is_event_system_shut_down": "false", "thread_groups": [{"name": "ET_NET", "count": "``", "started": "true"}, {"name": "ET_TASK", "count": "2", "started": "true"}, {"name": "ET_UDP", "count": "0", "started": "false"}]}'
45-
)
43+
traffic_ctl.server().status().validate_json_contains(
44+
initialized_done='true', is_ssl_handshaking_stopped='false', is_draining='false', is_event_system_shut_down='false')
4645
# Drain ats so we can check the output.
4746
traffic_ctl.server().drain().exec()
4847

4948
# After the drain, server status should reflect this change.
50-
traffic_ctl.server().status().validate_with_text(
51-
'{"initialized_done": "true", "is_ssl_handshaking_stopped": "false", "is_draining": "true", "is_event_system_shut_down": "false", "thread_groups": [{"name": "ET_NET", "count": "``", "started": "true"}, {"name": "ET_TASK", "count": "2", "started": "true"}, {"name": "ET_UDP", "count": "0", "started": "false"}]}'
52-
)
49+
traffic_ctl.server().status().validate_json_contains(initialized_done='true', is_draining='true')
5350

5451
# Get basic and empty connection tracker info.
5552
traffic_ctl.rpc().invoke(
@@ -58,11 +55,11 @@
5855
# default = outbound only
5956
traffic_ctl.rpc().invoke(
6057
handler="get_connection_tracker_info").validate_result_with_text('{"outbound": {"count": "0", "list": []}}')
61-
# requets inbound oonly
58+
# request inbound only
6259
traffic_ctl.rpc().invoke(
6360
handler="get_connection_tracker_info",
6461
params='"table: inbound"').validate_result_with_text('{"inbound": {"count": "0", "list": []}}')
65-
# requets outbound only
62+
# request outbound only
6663
traffic_ctl.rpc().invoke(
6764
handler="get_connection_tracker_info",
6865
params='"table: outbound"').validate_result_with_text('{"outbound": {"count": "0", "list": []}}')

tests/gold_tests/traffic_ctl/traffic_ctl_test_utils.py

Lines changed: 51 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,57 @@ def validate_with_exit_code(self, exit_code: int):
7171
self._finish_callback(self)
7272
return self
7373

74+
def validate_with_text(self, text: str):
75+
"""
76+
Validate command output matches expected text exactly.
77+
78+
Example:
79+
traffic_ctl.config().get("proxy.config.product_name").validate_with_text("Apache Traffic Server")
80+
"""
81+
self._tr.Processes.Default.Streams.stdout = MakeGoldFileWithText(text, self._dir, self._tn)
82+
self._finish_callback(self)
83+
return self
84+
85+
def validate_result_with_text(self, text: str):
86+
"""
87+
Validate RPC result matches expected JSON exactly. Wraps text in JSON-RPC envelope.
88+
89+
Example:
90+
traffic_ctl.rpc().invoke(handler="get_connection_tracker_info").validate_result_with_text(
91+
'{"outbound": {"count": "0", "list": []}}'
92+
)
93+
"""
94+
full_text = f'{{\"jsonrpc\": \"2.0\", \"result\": {text}, \"id\": {"``"}}}'
95+
self._tr.Processes.Default.Streams.stdout = MakeGoldFileWithText(full_text, self._dir, self._tn)
96+
self._finish_callback(self)
97+
return self
98+
99+
def validate_json_contains(self, **field_checks):
100+
"""
101+
Validate JSON output contains specific field:value pairs. Only checks specified fields.
102+
Prints detailed error on failure: "FAIL: field_name = actual_value (expected expected_value)"
103+
stream.all.txt will contain the actual output with the failed fields.
104+
105+
Example:
106+
traffic_ctl.server().status().validate_json_contains(
107+
initialized_done='true', is_draining='false'
108+
)
109+
"""
110+
import json
111+
checks_str = ', '.join(f"'{k}': '{v}'" for k, v in field_checks.items())
112+
self._cmd = (
113+
f'{self._cmd} | python3 -c "'
114+
f"import sys, json; "
115+
f"d = json.load(sys.stdin); "
116+
f"c = {{{checks_str}}}; "
117+
f"failed = [(k, v, str(d.get(k))) for k, v in c.items() if str(d.get(k)) != v]; "
118+
f"[print(f'FAIL: {{k}} = {{actual}} (expected {{expected}})', file=sys.stderr) "
119+
f"for k, expected, actual in failed]; "
120+
f"exit(0 if not failed else 1)"
121+
f'"')
122+
self._finish_callback(self)
123+
return self
124+
74125

75126
class Config(Common):
76127
"""
@@ -119,10 +170,6 @@ def validate_with_goldfile(self, file: str):
119170
self._tr.Processes.Default.Streams.stdout = os.path.join("gold", file)
120171
self.__finish()
121172

122-
def validate_with_text(self, text: str):
123-
self._tr.Processes.Default.Streams.stdout = MakeGoldFileWithText(text, self._dir, self._tn)
124-
self.__finish()
125-
126173

127174
class Server(Common):
128175
"""
@@ -165,10 +212,6 @@ def __finish(self):
165212
"""
166213
self._tr.Processes.Default.Command = self._cmd
167214

168-
def validate_with_text(self, text: str):
169-
self._tr.Processes.Default.Streams.stdout = MakeGoldFileWithText(text, self._dir, self._tn)
170-
self.__finish()
171-
172215

173216
class RPC(Common):
174217
"""
@@ -197,15 +240,6 @@ def __finish(self):
197240
"""
198241
self._tr.Processes.Default.Command = self._cmd
199242

200-
def validate_with_text(self, text: str):
201-
self._tr.Processes.Default.Streams.stdout = MakeGoldFileWithText(text, self._dir, self._tn)
202-
self.__finish()
203-
204-
def validate_result_with_text(self, text: str):
205-
full_text = f'{{\"jsonrpc\": \"2.0\", \"result\": {text}, \"id\": {"``"}}}'
206-
self._tr.Processes.Default.Streams.stdout = MakeGoldFileWithText(full_text, self._dir, self._tn)
207-
self.__finish()
208-
209243

210244
'''
211245

0 commit comments

Comments
 (0)