Files
higress/plugins/wasm-go/extensions/de-graphql/main_test.go

373 lines
11 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// 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"
)
// 测试配置:基本配置
var basicConfig = func() json.RawMessage {
data, _ := json.Marshal(map[string]interface{}{
"gql": `query ($owner: String!, $name: String!) {
repository(owner: $owner, name: $name) {
name
forkCount
description
}
}`,
"endpoint": "/graphql",
"timeout": 5000,
"domain": "api.github.com",
})
return data
}()
// 测试配置:带不同类型变量的配置
var multiTypeConfig = func() json.RawMessage {
data, _ := json.Marshal(map[string]interface{}{
"gql": `query ($id: Int!, $enabled: Boolean!, $score: Float!, $title: String!) {
item(id: $id, enabled: $enabled, score: $score, title: $title) {
id
name
status
}
}`,
"endpoint": "/api/graphql",
"timeout": 3000,
"domain": "example.com",
})
return data
}()
// 测试配置:可选参数配置
var optionalParamsConfig = func() json.RawMessage {
data, _ := json.Marshal(map[string]interface{}{
"gql": `query ($id: String, $name: String) {
user(id: $id, name: $name) {
id
name
email
}
}`,
"endpoint": "/graphql",
"timeout": 5000,
"domain": "api.example.com",
})
return data
}()
// 测试配置:默认值配置
var defaultConfig = func() json.RawMessage {
data, _ := json.Marshal(map[string]interface{}{
"gql": `query ($owner: String!) {
repository(owner: $owner) {
name
}
}`,
})
return data
}()
// 测试配置:无效 GraphQL 配置
var invalidGqlConfig = func() json.RawMessage {
data, _ := json.Marshal(map[string]interface{}{
"gql": "",
"endpoint": "/graphql",
"timeout": 5000,
"domain": "api.github.com",
})
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("multi type config", func(t *testing.T) {
host, status := test.NewTestHost(multiTypeConfig)
defer host.Reset()
require.Equal(t, types.OnPluginStartStatusOK, status)
config, err := host.GetMatchConfig()
require.NoError(t, err)
require.NotNil(t, config)
})
// 测试可选参数配置解析
t.Run("optional params config", func(t *testing.T) {
host, status := test.NewTestHost(optionalParamsConfig)
defer host.Reset()
require.Equal(t, types.OnPluginStartStatusOK, status)
config, err := host.GetMatchConfig()
require.NoError(t, err)
require.NotNil(t, config)
})
// 测试默认值配置解析
t.Run("default config", func(t *testing.T) {
host, status := test.NewTestHost(defaultConfig)
defer host.Reset()
require.Equal(t, types.OnPluginStartStatusOK, status)
config, err := host.GetMatchConfig()
require.NoError(t, err)
require.NotNil(t, config)
})
// 测试无效 GraphQL 配置解析
t.Run("invalid gql config", func(t *testing.T) {
host, status := test.NewTestHost(invalidGqlConfig)
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) {
// 测试基本 GraphQL 查询请求头处理
t.Run("basic graphql query", 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", "/api?owner=alibaba&name=higress"},
{":method", "GET"},
{"authorization", "Bearer token123"},
})
// 由于需要调用外部 GraphQL 服务,应该返回 ActionPause
require.Equal(t, types.ActionPause, action)
// 模拟外部 GraphQL 服务的HTTP调用响应
// 模拟成功响应200状态码
host.CallOnHttpCall([][2]string{
{":status", "200"},
{"content-type", "application/json"},
}, []byte(`{"data":{"repository":{"name":"higress","forkCount":149,"description":"Next-generation Cloud Native Gateway"}}}`))
host.CompleteHttp()
})
// 测试多类型变量查询请求头处理
t.Run("multi type variables query", func(t *testing.T) {
host, status := test.NewTestHost(multiTypeConfig)
defer host.Reset()
require.Equal(t, types.OnPluginStartStatusOK, status)
// 设置请求头,包含不同类型的查询参数
action := host.CallOnHttpRequestHeaders([][2]string{
{":authority", "example.com"},
{":path", "/api?id=123&enabled=true&score=95.5&title=Test Item"},
{":method", "GET"},
})
// 由于需要调用外部 GraphQL 服务,应该返回 ActionPause
require.Equal(t, types.ActionPause, action)
// 模拟外部 GraphQL 服务的HTTP调用响应
host.CallOnHttpCall([][2]string{
{":status", "200"},
{"content-type", "application/json"},
}, []byte(`{"data":{"item":{"id":123,"name":"Test Item","status":"active"}}}`))
host.CompleteHttp()
})
// 测试可选参数查询请求头处理
t.Run("optional parameters query", func(t *testing.T) {
host, status := test.NewTestHost(optionalParamsConfig)
defer host.Reset()
require.Equal(t, types.OnPluginStartStatusOK, status)
// 设置请求头,只包含部分查询参数
action := host.CallOnHttpRequestHeaders([][2]string{
{":authority", "example.com"},
{":path", "/api?name=john"},
{":method", "GET"},
})
// 由于需要调用外部 GraphQL 服务,应该返回 ActionPause
require.Equal(t, types.ActionPause, action)
// 模拟外部 GraphQL 服务的HTTP调用响应
host.CallOnHttpCall([][2]string{
{":status", "200"},
{"content-type", "application/json"},
}, []byte(`{"data":{"user":{"id":"user123","name":"john","email":"john@example.com"}}}`))
host.CompleteHttp()
})
// 测试无查询参数的请求头处理
t.Run("no query parameters", 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", "/api"},
{":method", "GET"},
})
// 由于需要调用外部 GraphQL 服务,应该返回 ActionPause
require.Equal(t, types.ActionPause, action)
// 模拟外部 GraphQL 服务的HTTP调用响应
host.CallOnHttpCall([][2]string{
{":status", "200"},
{"content-type", "application/json"},
}, []byte(`{"data":{"repository":null}}`))
host.CompleteHttp()
})
// 测试 POST 请求的请求头处理
t.Run("POST request", func(t *testing.T) {
host, status := test.NewTestHost(basicConfig)
defer host.Reset()
require.Equal(t, types.OnPluginStartStatusOK, status)
// 设置请求头POST 请求
action := host.CallOnHttpRequestHeaders([][2]string{
{":authority", "example.com"},
{":path", "/api?owner=alibaba&name=higress"},
{":method", "POST"},
{"content-type", "application/json"},
})
// 由于需要调用外部 GraphQL 服务,应该返回 ActionPause
require.Equal(t, types.ActionPause, action)
// 模拟外部 GraphQL 服务的HTTP调用响应
host.CallOnHttpCall([][2]string{
{":status", "200"},
{"content-type", "application/json"},
}, []byte(`{"data":{"repository":{"name":"higress","forkCount":149,"description":"Next-generation Cloud Native Gateway"}}}`))
host.CompleteHttp()
})
})
}
func TestOnHttpRequestBody(t *testing.T) {
test.RunTest(t, func(t *testing.T) {
// 测试请求体处理
t.Run("request body processing", func(t *testing.T) {
host, status := test.NewTestHost(basicConfig)
defer host.Reset()
require.Equal(t, types.OnPluginStartStatusOK, status)
// 先处理请求头
host.CallOnHttpRequestHeaders([][2]string{
{":authority", "example.com"},
{":path", "/api?owner=alibaba&name=higress"},
{":method", "POST"},
})
// 处理请求体
requestBody := `{"additional": "data"}`
action := host.CallOnHttpRequestBody([]byte(requestBody))
// 请求体处理应该返回 ActionContinue
require.Equal(t, types.ActionContinue, action)
host.CompleteHttp()
})
})
}
func TestOnHttpResponseHeaders(t *testing.T) {
test.RunTest(t, func(t *testing.T) {
// 测试响应头处理
t.Run("response headers processing", func(t *testing.T) {
host, status := test.NewTestHost(basicConfig)
defer host.Reset()
require.Equal(t, types.OnPluginStartStatusOK, status)
// 先处理请求头
host.CallOnHttpRequestHeaders([][2]string{
{":authority", "example.com"},
{":path", "/api?owner=alibaba&name=higress"},
{":method", "GET"},
})
// 处理响应头
action := host.CallOnHttpResponseHeaders([][2]string{
{":status", "200"},
{"content-type", "application/json"},
})
// 响应头处理应该返回 ActionContinue
require.Equal(t, types.ActionContinue, action)
host.CompleteHttp()
})
})
}
func TestOnHttpResponseBody(t *testing.T) {
test.RunTest(t, func(t *testing.T) {
// 测试响应体处理
t.Run("response body processing", func(t *testing.T) {
host, status := test.NewTestHost(basicConfig)
defer host.Reset()
require.Equal(t, types.OnPluginStartStatusOK, status)
// 先处理请求头
host.CallOnHttpRequestHeaders([][2]string{
{":authority", "example.com"},
{":path", "/api?owner=alibaba&name=higress"},
{":method", "GET"},
})
// 处理响应体
responseBody := `{"data":{"repository":{"name":"higress","forkCount":149,"description":"Next-generation Cloud Native Gateway"}}}`
action := host.CallOnHttpResponseBody([]byte(responseBody))
// 响应体处理应该返回 ActionContinue
require.Equal(t, types.ActionContinue, action)
host.CompleteHttp()
})
})
}