mirror of
https://github.com/alibaba/higress.git
synced 2026-06-09 04:37:31 +08:00
feat(wasm-go): add wasm go plugin unit test and ci workflow (#2809)
This commit is contained in:
@@ -1,7 +1,26 @@
|
||||
// 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 main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"testing"
|
||||
|
||||
"github.com/higress-group/proxy-wasm-go-sdk/proxywasm/types"
|
||||
"github.com/higress-group/wasm-go/pkg/test"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func Test_prefixMatchCode(t *testing.T) {
|
||||
@@ -78,3 +97,442 @@ func TestIsValidPrefixString(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 测试配置:基本配置(老版本)
|
||||
var basicConfig = func() json.RawMessage {
|
||||
data, _ := json.Marshal(map[string]interface{}{
|
||||
"status_code": 200,
|
||||
"headers": []string{
|
||||
"Content-Type=application/json",
|
||||
"Hello=World",
|
||||
},
|
||||
"body": `{"hello":"world"}`,
|
||||
})
|
||||
return data
|
||||
}()
|
||||
|
||||
// 测试配置:带状态码匹配的配置(老版本)
|
||||
var statusMatchConfig = func() json.RawMessage {
|
||||
data, _ := json.Marshal(map[string]interface{}{
|
||||
"status_code": 302,
|
||||
"headers": []string{
|
||||
"Location=https://example.com",
|
||||
},
|
||||
"body": "Redirect to example.com",
|
||||
"enable_on_status": []string{
|
||||
"429",
|
||||
},
|
||||
})
|
||||
return data
|
||||
}()
|
||||
|
||||
// 测试配置:新版本多规则配置
|
||||
var multiRulesConfig = func() json.RawMessage {
|
||||
data, _ := json.Marshal(map[string]interface{}{
|
||||
"rules": []map[string]interface{}{
|
||||
{
|
||||
"body": `{"hello":"world 200"}`,
|
||||
"enable_on_status": []string{
|
||||
"200",
|
||||
"201",
|
||||
},
|
||||
"headers": []string{
|
||||
"key1=value1",
|
||||
"key2=value2",
|
||||
},
|
||||
"status_code": 200,
|
||||
},
|
||||
{
|
||||
"body": `{"hello":"world 404"}`,
|
||||
"enable_on_status": []string{
|
||||
"404",
|
||||
},
|
||||
"headers": []string{
|
||||
"key1=value1",
|
||||
"key2=value2",
|
||||
},
|
||||
"status_code": 200,
|
||||
},
|
||||
},
|
||||
})
|
||||
return data
|
||||
}()
|
||||
|
||||
// 测试配置:模糊匹配配置
|
||||
var fuzzyMatchConfig = func() json.RawMessage {
|
||||
data, _ := json.Marshal(map[string]interface{}{
|
||||
"rules": []map[string]interface{}{
|
||||
{
|
||||
"body": `{"hello":"world 200"}`,
|
||||
"enable_on_status": []string{
|
||||
"200",
|
||||
},
|
||||
"headers": []string{
|
||||
"key1=value1",
|
||||
"key2=value2",
|
||||
},
|
||||
"status_code": 200,
|
||||
},
|
||||
{
|
||||
"body": `{"hello":"world 40x"}`,
|
||||
"enable_on_status": []string{
|
||||
"40x",
|
||||
},
|
||||
"headers": []string{
|
||||
"key1=value1",
|
||||
"key2=value2",
|
||||
},
|
||||
"status_code": 200,
|
||||
},
|
||||
{
|
||||
"body": `{"hello":"world 4xx"}`,
|
||||
"enable_on_status": []string{
|
||||
"4xx",
|
||||
},
|
||||
"headers": []string{
|
||||
"key1=value1",
|
||||
"key2=value2",
|
||||
},
|
||||
"status_code": 200,
|
||||
},
|
||||
},
|
||||
})
|
||||
return data
|
||||
}()
|
||||
|
||||
// 测试配置:带默认规则的配置
|
||||
var defaultRuleConfig = func() json.RawMessage {
|
||||
data, _ := json.Marshal(map[string]interface{}{
|
||||
"rules": []map[string]interface{}{
|
||||
{
|
||||
"body": `{"hello":"world default"}`,
|
||||
"headers": []string{
|
||||
"key1=value1",
|
||||
"key2=value2",
|
||||
},
|
||||
"status_code": 200,
|
||||
},
|
||||
{
|
||||
"body": `{"hello":"world 404"}`,
|
||||
"enable_on_status": []string{
|
||||
"404",
|
||||
},
|
||||
"headers": []string{
|
||||
"key1=value1",
|
||||
"key2=value2",
|
||||
},
|
||||
"status_code": 200,
|
||||
},
|
||||
},
|
||||
})
|
||||
return data
|
||||
}()
|
||||
|
||||
// 测试配置:纯默认规则配置(没有 enable_on_status)
|
||||
var pureDefaultRuleConfig = func() json.RawMessage {
|
||||
data, _ := json.Marshal(map[string]interface{}{
|
||||
"rules": []map[string]interface{}{
|
||||
{
|
||||
"body": `{"hello":"world pure default"}`,
|
||||
"headers": []string{
|
||||
"key1=value1",
|
||||
"key2=value2",
|
||||
},
|
||||
"status_code": 200,
|
||||
},
|
||||
},
|
||||
})
|
||||
return data
|
||||
}()
|
||||
|
||||
// 测试配置:无效配置
|
||||
var invalidConfig = func() json.RawMessage {
|
||||
data, _ := json.Marshal(map[string]interface{}{
|
||||
"rules": []map[string]interface{}{
|
||||
{
|
||||
"body": `{"hello":"world"}`,
|
||||
"enable_on_status": []string{
|
||||
"invalid",
|
||||
},
|
||||
"headers": []string{
|
||||
"key1=value1",
|
||||
},
|
||||
"status_code": 200,
|
||||
},
|
||||
},
|
||||
})
|
||||
return data
|
||||
}()
|
||||
|
||||
func TestParseConfig(t *testing.T) {
|
||||
test.RunGoTest(t, func(t *testing.T) {
|
||||
// 测试基本配置解析(老版本)
|
||||
t.Run("basic config", func(t *testing.T) {
|
||||
host, status := test.NewTestHost(basicConfig)
|
||||
defer host.Reset()
|
||||
require.Equal(t, types.OnPluginStartStatusOK, status)
|
||||
|
||||
config, err := host.GetMatchConfig()
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, config)
|
||||
})
|
||||
|
||||
// 测试状态码匹配配置解析(老版本)
|
||||
t.Run("status match config", func(t *testing.T) {
|
||||
host, status := test.NewTestHost(statusMatchConfig)
|
||||
defer host.Reset()
|
||||
require.Equal(t, types.OnPluginStartStatusOK, status)
|
||||
|
||||
config, err := host.GetMatchConfig()
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, config)
|
||||
})
|
||||
|
||||
// 测试多规则配置解析(新版本)
|
||||
t.Run("multi rules config", func(t *testing.T) {
|
||||
host, status := test.NewTestHost(multiRulesConfig)
|
||||
defer host.Reset()
|
||||
require.Equal(t, types.OnPluginStartStatusOK, status)
|
||||
|
||||
config, err := host.GetMatchConfig()
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, config)
|
||||
})
|
||||
|
||||
// 测试模糊匹配配置解析
|
||||
t.Run("fuzzy match config", func(t *testing.T) {
|
||||
host, status := test.NewTestHost(fuzzyMatchConfig)
|
||||
defer host.Reset()
|
||||
require.Equal(t, types.OnPluginStartStatusOK, status)
|
||||
|
||||
config, err := host.GetMatchConfig()
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, config)
|
||||
})
|
||||
|
||||
// 测试带默认规则的配置解析
|
||||
t.Run("default rule config", func(t *testing.T) {
|
||||
host, status := test.NewTestHost(defaultRuleConfig)
|
||||
defer host.Reset()
|
||||
require.Equal(t, types.OnPluginStartStatusOK, status)
|
||||
|
||||
config, err := host.GetMatchConfig()
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, config)
|
||||
})
|
||||
|
||||
// 测试无效配置解析
|
||||
t.Run("invalid config", func(t *testing.T) {
|
||||
host, status := test.NewTestHost(invalidConfig)
|
||||
defer host.Reset()
|
||||
require.Equal(t, types.OnPluginStartStatusFailed, status)
|
||||
|
||||
config, err := host.GetMatchConfig()
|
||||
require.NoError(t, err)
|
||||
require.Nil(t, config)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
func TestOnHttpRequestHeaders(t *testing.T) {
|
||||
test.RunTest(t, func(t *testing.T) {
|
||||
// 测试基本配置的请求头处理(应该使用默认规则)
|
||||
t.Run("basic config request headers", func(t *testing.T) {
|
||||
host, status := test.NewTestHost(basicConfig)
|
||||
defer host.Reset()
|
||||
require.Equal(t, types.OnPluginStartStatusOK, status)
|
||||
|
||||
// 设置请求头
|
||||
action := host.CallOnHttpRequestHeaders([][2]string{
|
||||
{":authority", "example.com"},
|
||||
{":path", "/test"},
|
||||
{":method", "GET"},
|
||||
})
|
||||
|
||||
// 由于没有 enable_on_status 规则,应该使用默认规则并返回 ActionPause
|
||||
require.Equal(t, types.ActionPause, action)
|
||||
|
||||
host.CompleteHttp()
|
||||
})
|
||||
|
||||
// 测试带状态码匹配的请求头处理(不应该在请求头阶段处理)
|
||||
t.Run("status match config request headers", func(t *testing.T) {
|
||||
host, status := test.NewTestHost(statusMatchConfig)
|
||||
defer host.Reset()
|
||||
require.Equal(t, types.OnPluginStartStatusOK, status)
|
||||
|
||||
// 设置请求头
|
||||
action := host.CallOnHttpRequestHeaders([][2]string{
|
||||
{":authority", "example.com"},
|
||||
{":path", "/test"},
|
||||
{":method", "GET"},
|
||||
})
|
||||
|
||||
// 由于有 enable_on_status 规则,应该返回 ActionContinue
|
||||
require.Equal(t, types.ActionContinue, action)
|
||||
|
||||
host.CompleteHttp()
|
||||
})
|
||||
|
||||
// 测试多规则配置的请求头处理(不应该在请求头阶段处理)
|
||||
t.Run("multi rules config request headers", func(t *testing.T) {
|
||||
host, status := test.NewTestHost(multiRulesConfig)
|
||||
defer host.Reset()
|
||||
require.Equal(t, types.OnPluginStartStatusOK, status)
|
||||
|
||||
// 设置请求头
|
||||
action := host.CallOnHttpRequestHeaders([][2]string{
|
||||
{":authority", "example.com"},
|
||||
{":path", "/test"},
|
||||
{":method", "GET"},
|
||||
})
|
||||
|
||||
// 由于有 enable_on_status 规则,应该返回 ActionContinue
|
||||
require.Equal(t, types.ActionContinue, action)
|
||||
|
||||
host.CompleteHttp()
|
||||
})
|
||||
|
||||
// 测试带默认规则的请求头处理(由于有 enable_on_status 规则,应该返回 ActionContinue)
|
||||
t.Run("default rule config request headers", func(t *testing.T) {
|
||||
host, status := test.NewTestHost(defaultRuleConfig)
|
||||
defer host.Reset()
|
||||
require.Equal(t, types.OnPluginStartStatusOK, status)
|
||||
|
||||
// 设置请求头
|
||||
action := host.CallOnHttpRequestHeaders([][2]string{
|
||||
{":authority", "example.com"},
|
||||
{":path", "/test"},
|
||||
{":method", "GET"},
|
||||
})
|
||||
|
||||
// 由于有 enable_on_status 规则,应该返回 ActionContinue
|
||||
require.Equal(t, types.ActionContinue, action)
|
||||
|
||||
host.CompleteHttp()
|
||||
})
|
||||
|
||||
// 测试纯默认规则的请求头处理(应该使用默认规则并返回 ActionPause)
|
||||
t.Run("pure default rule config request headers", func(t *testing.T) {
|
||||
host, status := test.NewTestHost(pureDefaultRuleConfig)
|
||||
defer host.Reset()
|
||||
require.Equal(t, types.OnPluginStartStatusOK, status)
|
||||
|
||||
// 设置请求头
|
||||
action := host.CallOnHttpRequestHeaders([][2]string{
|
||||
{":authority", "example.com"},
|
||||
{":path", "/test"},
|
||||
{":method", "GET"},
|
||||
})
|
||||
|
||||
// 由于没有 enable_on_status 规则,应该使用默认规则并返回 ActionPause
|
||||
require.Equal(t, types.ActionPause, action)
|
||||
|
||||
host.CompleteHttp()
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
func TestOnHttpResponseHeaders(t *testing.T) {
|
||||
test.RunTest(t, func(t *testing.T) {
|
||||
// 测试状态码匹配的响应头处理
|
||||
t.Run("status match response headers", func(t *testing.T) {
|
||||
host, status := test.NewTestHost(statusMatchConfig)
|
||||
defer host.Reset()
|
||||
require.Equal(t, types.OnPluginStartStatusOK, status)
|
||||
|
||||
// 先处理请求头
|
||||
host.CallOnHttpRequestHeaders([][2]string{
|
||||
{":authority", "example.com"},
|
||||
{":path", "/test"},
|
||||
{":method", "GET"},
|
||||
})
|
||||
|
||||
// 处理响应头,状态码为 429(应该匹配规则)
|
||||
action := host.CallOnHttpResponseHeaders([][2]string{
|
||||
{":status", "429"},
|
||||
{"content-type", "text/plain"},
|
||||
})
|
||||
|
||||
// 应该返回 ActionContinue
|
||||
require.Equal(t, types.ActionContinue, action)
|
||||
|
||||
host.CompleteHttp()
|
||||
})
|
||||
|
||||
// 测试多规则配置的响应头处理
|
||||
t.Run("multi rules response headers", func(t *testing.T) {
|
||||
host, status := test.NewTestHost(multiRulesConfig)
|
||||
defer host.Reset()
|
||||
require.Equal(t, types.OnPluginStartStatusOK, status)
|
||||
|
||||
// 先处理请求头
|
||||
host.CallOnHttpRequestHeaders([][2]string{
|
||||
{":authority", "example.com"},
|
||||
{":path", "/test"},
|
||||
{":method", "GET"},
|
||||
})
|
||||
|
||||
// 处理响应头,状态码为 200(应该匹配第一个规则)
|
||||
action := host.CallOnHttpResponseHeaders([][2]string{
|
||||
{":status", "200"},
|
||||
{"content-type", "text/plain"},
|
||||
})
|
||||
|
||||
// 应该返回 ActionContinue
|
||||
require.Equal(t, types.ActionContinue, action)
|
||||
|
||||
host.CompleteHttp()
|
||||
})
|
||||
|
||||
// 测试模糊匹配的响应头处理
|
||||
t.Run("fuzzy match response headers", func(t *testing.T) {
|
||||
host, status := test.NewTestHost(fuzzyMatchConfig)
|
||||
defer host.Reset()
|
||||
require.Equal(t, types.OnPluginStartStatusOK, status)
|
||||
|
||||
// 先处理请求头
|
||||
host.CallOnHttpRequestHeaders([][2]string{
|
||||
{":authority", "example.com"},
|
||||
{":path", "/test"},
|
||||
{":method", "GET"},
|
||||
})
|
||||
|
||||
// 处理响应头,状态码为 404(应该匹配 4xx 规则)
|
||||
action := host.CallOnHttpResponseHeaders([][2]string{
|
||||
{":status", "404"},
|
||||
{"content-type", "text/plain"},
|
||||
})
|
||||
|
||||
// 应该返回 ActionContinue
|
||||
require.Equal(t, types.ActionContinue, action)
|
||||
|
||||
host.CompleteHttp()
|
||||
})
|
||||
|
||||
// 测试不匹配状态码的响应头处理
|
||||
t.Run("no match response headers", func(t *testing.T) {
|
||||
host, status := test.NewTestHost(multiRulesConfig)
|
||||
defer host.Reset()
|
||||
require.Equal(t, types.OnPluginStartStatusOK, status)
|
||||
|
||||
// 先处理请求头
|
||||
host.CallOnHttpRequestHeaders([][2]string{
|
||||
{":authority", "example.com"},
|
||||
{":path", "/test"},
|
||||
{":method", "GET"},
|
||||
})
|
||||
|
||||
// 处理响应头,状态码为 500(不应该匹配任何规则)
|
||||
action := host.CallOnHttpResponseHeaders([][2]string{
|
||||
{":status", "500"},
|
||||
{"content-type", "text/plain"},
|
||||
})
|
||||
|
||||
// 应该返回 ActionContinue
|
||||
require.Equal(t, types.ActionContinue, action)
|
||||
|
||||
host.CompleteHttp()
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user