This is an automated email from the ASF dual-hosted git repository.
bneradt 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 799c4cc89a TSHttpAltInfoQualitySet: add an autest (#13391)
799c4cc89a is described below
commit 799c4cc89a64972d93716e23ddba9ede099b50f5
Author: Brian Neradt <[email protected]>
AuthorDate: Thu Jul 30 09:04:49 2026 -0500
TSHttpAltInfoQualitySet: add an autest (#13391)
This adds an AuTest to verify the TSHttpAltInfoQualitySet plugin API.
The test verifies alternate creation and selection through observable
cached responses.
Closes: #7205
---
tests/gold_tests/cache/alternate-caching.test.py | 8 +-
.../cache/replay/alternate-caching-quality.yaml | 142 +++++++++++++++++++++
tests/tools/plugins/CMakeLists.txt | 1 +
tests/tools/plugins/http_alt_info_quality.cc | 101 +++++++++++++++
4 files changed, 251 insertions(+), 1 deletion(-)
diff --git a/tests/gold_tests/cache/alternate-caching.test.py
b/tests/gold_tests/cache/alternate-caching.test.py
index b6ec135083..7f3b698c67 100644
--- a/tests/gold_tests/cache/alternate-caching.test.py
+++ b/tests/gold_tests/cache/alternate-caching.test.py
@@ -17,9 +17,15 @@ Test the alternate caching features
# See the License for the specific language governing permissions and
# limitations under the License.
+import os
+
Test.Summary = '''
Test the alternate caching feature.
'''
-# Verify disabled negative revalidating behavior.
+# Verify cache alternate replacement behavior.
Test.ATSReplayTest(replay_file="replay/alternate-caching-update-size.yaml")
+
+# Verify TSHttpAltInfoQualitySet affects alternate selection.
+tr = Test.ATSReplayTest(replay_file="replay/alternate-caching-quality.yaml")
+Test.PrepareTestPlugin(os.path.join(Test.Variables.AtsTestPluginsDir,
'http_alt_info_quality.so'), tr.Processes.ts_alt_quality)
diff --git a/tests/gold_tests/cache/replay/alternate-caching-quality.yaml
b/tests/gold_tests/cache/replay/alternate-caching-quality.yaml
new file mode 100644
index 0000000000..06915997fd
--- /dev/null
+++ b/tests/gold_tests/cache/replay/alternate-caching-quality.yaml
@@ -0,0 +1,142 @@
+# 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.
+
+meta:
+ version: "1.0"
+
+autest:
+ description: 'Verify TSHttpAltInfoQualitySet affects alternate selection'
+
+ dns:
+ name: 'dns_alt_quality'
+
+ server:
+ name: 'server_alt_quality'
+
+ client:
+ name: 'client_alt_quality'
+
+ ats:
+ name: 'ts_alt_quality'
+ process_config:
+ enable_cache: true
+
+ records_config:
+ proxy.config.cache.select_alternate: 1
+ proxy.config.cache.limits.http.max_alts: 4
+ proxy.config.http.cache.ignore_query: 1
+
+ plugin_config:
+ - "xdebug.so --enable=x-cache"
+
+ remap_config:
+ - from: "http://example.com/"
+ to: "http://backend.example.com:{SERVER_HTTP_PORT}/"
+
+sessions:
+- transactions:
+ # Store the English response as the first alternate.
+ - all: { headers: { fields: [[ uuid, 1 ]]}}
+ client-request:
+ method: "GET"
+ version: "1.1"
+ scheme: "http"
+ url: /path/request?variant=English
+ delay: 100ms
+ headers:
+ fields:
+ - [ Host, example.com ]
+ - [ Accept-Language, English ]
+ - [ X-Debug, X-Cache ]
+
+ server-response:
+ status: 200
+ reason: OK
+ headers:
+ fields:
+ - [ Content-Length, 0 ]
+ - [ Cache-Control, max-age=60 ]
+ - [ Content-Language, English ]
+ - [ X-Response-Variant, English ]
+
+ proxy-response:
+ status: 200
+ headers:
+ fields:
+ - [ X-Response-Variant, { value: English, as: equal } ]
+ - [ X-Cache, { value: miss, as: equal } ]
+
+ # The language mismatch prevents reuse of the English alternate, allowing
+ # the French response to be stored as another alternate.
+ - all: { headers: { fields: [[ uuid, 2 ]]}}
+ client-request:
+ method: "GET"
+ version: "1.1"
+ scheme: "http"
+ url: /path/request?variant=French
+ delay: 100ms
+ headers:
+ fields:
+ - [ Host, example.com ]
+ - [ Accept-Language, French ]
+ - [ X-Debug, X-Cache ]
+
+ server-response:
+ status: 200
+ reason: OK
+ headers:
+ fields:
+ - [ Content-Length, 0 ]
+ - [ Cache-Control, max-age=60 ]
+ - [ Content-Language, French ]
+ - [ X-Response-Variant, French ]
+
+ proxy-response:
+ status: 200
+ headers:
+ fields:
+ - [ X-Response-Variant, { value: French, as: equal } ]
+ - [ X-Cache, { value: miss, as: equal } ]
+
+ # Both languages are acceptable, so the plugin's query-based quality
+ # selects the older English alternate without contacting the origin.
+ - all: { headers: { fields: [[ uuid, 3 ]]}}
+ client-request:
+ method: "GET"
+ version: "1.1"
+ scheme: "http"
+ url: /path/request?variant=English
+ delay: 100ms
+ headers:
+ fields:
+ - [ Host, example.com ]
+ - [ Accept-Language, "English, French" ]
+ - [ X-Debug, X-Cache ]
+
+ proxy-request:
+ expect: absent
+
+ server-response:
+ status: 500
+ reason: NOT USED
+
+ proxy-response:
+ status: 200
+ headers:
+ fields:
+ - [ X-Response-Variant, { value: English, as: equal } ]
+ - [ X-Cache, { value: hit-fresh, as: equal } ]
diff --git a/tests/tools/plugins/CMakeLists.txt
b/tests/tools/plugins/CMakeLists.txt
index a909cf59d1..b7f18109ef 100644
--- a/tests/tools/plugins/CMakeLists.txt
+++ b/tests/tools/plugins/CMakeLists.txt
@@ -24,6 +24,7 @@ add_autest_plugin(delay_txn_start delay_txn_start.cc)
add_autest_plugin(emergency_shutdown emergency_shutdown.cc)
add_autest_plugin(fatal_shutdown fatal_shutdown.cc)
add_autest_plugin(hook_add_plugin hook_add_plugin.cc)
+add_autest_plugin(http_alt_info_quality http_alt_info_quality.cc)
add_autest_plugin(missing_mangled_definition missing_mangled_definition_c.c
missing_mangled_definition_cpp.cc)
add_autest_plugin(missing_ts_plugin_init missing_ts_plugin_init.cc)
add_autest_plugin(server_packet_mark server_packet_mark.cc
packet_mark_common.cc)
diff --git a/tests/tools/plugins/http_alt_info_quality.cc
b/tests/tools/plugins/http_alt_info_quality.cc
new file mode 100644
index 0000000000..dcd180d4a5
--- /dev/null
+++ b/tests/tools/plugins/http_alt_info_quality.cc
@@ -0,0 +1,101 @@
+/** @file
+
+ Select cache alternates by matching request query strings.
+
+ @section license License
+
+ 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.
+ */
+
+#include <ts/ts.h>
+
+#include <string>
+
+namespace
+{
+constexpr char PLUGIN_NAME[] = "http_alt_info_quality";
+
+std::string
+get_query(TSMBuffer buffer, TSMLoc header)
+{
+ TSMLoc url;
+ int length = 0;
+
+ if (TSHttpHdrUrlGet(buffer, header, &url) != TS_SUCCESS) {
+ return {};
+ }
+
+ const char *query = TSUrlHttpQueryGet(buffer, url, &length);
+ std::string result;
+
+ if (query != nullptr) {
+ result.assign(query, static_cast<size_t>(length));
+ }
+
+ TSHandleMLocRelease(buffer, header, url);
+ return result;
+}
+
+int
+select_alternate(TSCont /* contp ATS_UNUSED */, TSEvent event, void *edata)
+{
+ TSAssert(event == TS_EVENT_HTTP_SELECT_ALT);
+
+ auto alt_info = static_cast<TSHttpAltInfo>(edata);
+ TSMBuffer client_buffer;
+ TSMBuffer cached_buffer;
+ TSMLoc client_header;
+ TSMLoc cached_header;
+
+ if (TSHttpAltInfoClientReqGet(alt_info, &client_buffer, &client_header) !=
TS_SUCCESS) {
+ TSHttpAltInfoQualitySet(alt_info, 0.0F);
+ return 0;
+ }
+ if (TSHttpAltInfoCachedReqGet(alt_info, &cached_buffer, &cached_header) !=
TS_SUCCESS) {
+ TSHttpAltInfoQualitySet(alt_info, 0.0F);
+ TSHandleMLocRelease(client_buffer, TS_NULL_MLOC, client_header);
+ return 0;
+ }
+
+ std::string client_query = get_query(client_buffer, client_header);
+ std::string cached_query = get_query(cached_buffer, cached_header);
+
+ TSHttpAltInfoQualitySet(alt_info, client_query == cached_query ? 1.0F :
0.0F);
+
+ TSHandleMLocRelease(client_buffer, TS_NULL_MLOC, client_header);
+ TSHandleMLocRelease(cached_buffer, TS_NULL_MLOC, cached_header);
+ return 0;
+}
+} // namespace
+
+void
+TSPluginInit(int /* argc ATS_UNUSED */, const char ** /* argv ATS_UNUSED */)
+{
+ TSPluginRegistrationInfo info;
+
+ info.plugin_name = PLUGIN_NAME;
+ info.vendor_name = "Apache Software Foundation";
+ info.support_email = "[email protected]";
+
+ if (TSPluginRegister(&info) != TS_SUCCESS) {
+ TSError("[%s] plugin registration failed", PLUGIN_NAME);
+ return;
+ }
+
+ TSHttpHookAdd(TS_HTTP_SELECT_ALT_HOOK, TSContCreate(select_alternate,
nullptr));
+}