From 678ea5660e6537b31d75c89f930b1822a9d5b40e Mon Sep 17 00:00:00 2001 From: Jingze <52855280+Jing-ze@users.noreply.github.com> Date: Tue, 12 May 2026 10:19:36 +0800 Subject: [PATCH] fix(wasm): resolve stale route_name in wasm context after reroute (#3576) Signed-off-by: jingze --- .../tests/go-wasm-reroute-match-rule.go | 101 ++++++++++++++++++ .../tests/go-wasm-reroute-match-rule.yaml | 99 +++++++++++++++++ 2 files changed, 200 insertions(+) create mode 100644 test/e2e/conformance/tests/go-wasm-reroute-match-rule.go create mode 100644 test/e2e/conformance/tests/go-wasm-reroute-match-rule.yaml diff --git a/test/e2e/conformance/tests/go-wasm-reroute-match-rule.go b/test/e2e/conformance/tests/go-wasm-reroute-match-rule.go new file mode 100644 index 00000000..672fbaa1 --- /dev/null +++ b/test/e2e/conformance/tests/go-wasm-reroute-match-rule.go @@ -0,0 +1,101 @@ +// Copyright (c) 2022 Alibaba Group Holding Ltd. +// +// Licensed 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. + +package tests + +import ( + "testing" + + "github.com/alibaba/higress/v2/test/e2e/conformance/utils/http" + "github.com/alibaba/higress/v2/test/e2e/conformance/utils/suite" +) + +func init() { + Register(WasmPluginsRerouteMatchRule) +} + +// WasmPluginsRerouteMatchRule tests that wasm plugin matchRules work correctly +// after a reroute triggered by a previous plugin (issue #3571). +// +// Scenario: +// - Ingress "reroute-match-default": host reroute-match.com, path /, no header constraint +// - Ingress "reroute-match-target": host reroute-match.com, path /, header x-user-id: 1 +// - Plugin A (transformer, priority 400): matchRule for "reroute-match-default", +// maps query param "userId" to header "x-user-id", causing reroute +// - Plugin B (custom-response, priority 200): matchRule for "reroute-match-target", +// returns custom response {"hello":"world"} +// +// When sending GET /?userId=1, plugin A adds x-user-id:1 header and triggers reroute. +// Plugin B should see the NEW route "reroute-match-target" and return the custom response. +var WasmPluginsRerouteMatchRule = suite.ConformanceTest{ + ShortName: "WasmPluginsRerouteMatchRule", + Description: "Tests that wasm plugin matchRules work correctly after reroute triggered by a previous plugin (issue #3571).", + Manifests: []string{"tests/go-wasm-reroute-match-rule.yaml"}, + Features: []suite.SupportedFeature{suite.WASMGoConformanceFeature}, + Test: func(t *testing.T, suite *suite.ConformanceTestSuite) { + testcases := []http.Assertion{ + { + Meta: http.AssertionMeta{ + TestCaseName: "case 1: matchRule should work after reroute - custom response expected", + CompareTarget: http.CompareTargetResponse, + }, + Request: http.AssertionRequest{ + ActualRequest: http.Request{ + Host: "reroute-match.com", + Path: "/?userId=1", + }, + }, + Response: http.AssertionResponse{ + ExpectedResponse: http.Response{ + StatusCode: 200, + Headers: map[string]string{ + "x-matched": "rerouted", + }, + ContentType: http.ContentTypeApplicationJson, + Body: []byte("{\"hello\":\"world\"}"), + }, + }, + }, + { + Meta: http.AssertionMeta{ + TestCaseName: "case 2: no reroute without userId param - normal backend response", + TargetBackend: "infra-backend-v1", + TargetNamespace: "higress-conformance-infra", + }, + Request: http.AssertionRequest{ + ActualRequest: http.Request{ + Host: "reroute-match.com", + Path: "/get", + }, + ExpectedRequest: &http.ExpectedRequest{ + Request: http.Request{ + Host: "reroute-match.com", + Path: "/get", + }, + }, + }, + Response: http.AssertionResponse{ + ExpectedResponse: http.Response{ + StatusCode: 200, + }, + }, + }, + } + t.Run("WasmPlugins reroute match rule", func(t *testing.T) { + for _, testcase := range testcases { + http.MakeRequestAndExpectEventuallyConsistentResponse(t, suite.RoundTripper, suite.TimeoutConfig, suite.GatewayAddress, testcase) + } + }) + }, +} diff --git a/test/e2e/conformance/tests/go-wasm-reroute-match-rule.yaml b/test/e2e/conformance/tests/go-wasm-reroute-match-rule.yaml new file mode 100644 index 00000000..d8bc69b0 --- /dev/null +++ b/test/e2e/conformance/tests/go-wasm-reroute-match-rule.yaml @@ -0,0 +1,99 @@ +# Copyright (c) 2022 Alibaba Group Holding Ltd. +# +# Licensed 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. + +# This test reproduces the bug described in https://github.com/alibaba/higress/issues/3571 +# When plugin A (transformer) modifies headers causing a reroute, plugin B (custom-response) +# should see the NEW route name in its matchRule evaluation. Due to a bug in ROUTE_NAME +# property resolution, the stale old route name is returned after clearRouteCache(). + +# Default ingress: matches requests to reroute-match.com without x-user-id header +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: reroute-match-default + namespace: higress-conformance-infra +spec: + ingressClassName: higress + rules: + - host: "reroute-match.com" + http: + paths: + - pathType: Prefix + path: "/" + backend: + service: + name: infra-backend-v1 + port: + number: 8080 +--- +# Target ingress: matches requests to reroute-match.com WITH x-user-id: 1 header +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + annotations: + higress.io/exact-match-header-x-user-id: "1" + name: reroute-match-target + namespace: higress-conformance-infra +spec: + ingressClassName: higress + rules: + - host: "reroute-match.com" + http: + paths: + - pathType: Prefix + path: "/" + backend: + service: + name: infra-backend-v1 + port: + number: 8080 +--- +# Transformer plugin (priority 400, runs first): +# Maps query param "userId" to header "x-user-id", triggering a reroute +apiVersion: extensions.higress.io/v1alpha1 +kind: WasmPlugin +metadata: + name: reroute-transformer + namespace: higress-system +spec: + priority: 400 + matchRules: + - ingress: + - higress-conformance-infra/reroute-match-default + config: + reqRules: + - operate: map + mapSource: querys + headers: + - fromKey: userId + toKey: x-user-id + url: file:///opt/plugins/wasm-go/extensions/transformer/plugin.wasm +--- +# Custom-response plugin (priority 200, runs after transformer): +# Should activate on the rerouted target route and return custom response +apiVersion: extensions.higress.io/v1alpha1 +kind: WasmPlugin +metadata: + name: reroute-custom-response + namespace: higress-system +spec: + priority: 200 + matchRules: + - ingress: + - higress-conformance-infra/reroute-match-target + config: + headers: + - x-matched=rerouted + "body": '{"hello":"world"}' + url: oci://higress-registry.cn-hangzhou.cr.aliyuncs.com/plugins/go-custom-response:2.0.0