mirror of
https://github.com/alibaba/higress.git
synced 2026-03-19 01:37:28 +08:00
feat: add e2e test for envoy filter (#710)
This commit is contained in:
@@ -18,6 +18,7 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/alibaba/higress/pkg/ingress/kube/configmap"
|
||||
"github.com/alibaba/higress/test/e2e/conformance/utils/envoy"
|
||||
"github.com/alibaba/higress/test/e2e/conformance/utils/http"
|
||||
"github.com/alibaba/higress/test/e2e/conformance/utils/kubernetes"
|
||||
"github.com/alibaba/higress/test/e2e/conformance/utils/suite"
|
||||
@@ -25,6 +26,266 @@ import (
|
||||
|
||||
func init() {
|
||||
Register(ConfigmapGzip)
|
||||
Register(ConfigMapGzipEnvoy)
|
||||
}
|
||||
|
||||
var testCases = []struct {
|
||||
higressConfig *configmap.HigressConfig
|
||||
envoyAssertion envoy.Assertion
|
||||
httpAssert http.Assertion
|
||||
}{
|
||||
{
|
||||
higressConfig: &configmap.HigressConfig{
|
||||
Gzip: &configmap.Gzip{
|
||||
Enable: false,
|
||||
MinContentLength: 1024,
|
||||
ContentType: []string{"text/html", "text/css", "text/plain", "text/xml", "application/json", "application/javascript", "application/xhtml+xml", "image/svg+xml"},
|
||||
DisableOnEtagHeader: true,
|
||||
MemoryLevel: 5,
|
||||
WindowBits: 12,
|
||||
ChunkSize: 4096,
|
||||
CompressionLevel: "BEST_COMPRESSION",
|
||||
CompressionStrategy: "DEFAULT_STRATEGY",
|
||||
},
|
||||
},
|
||||
httpAssert: http.Assertion{
|
||||
Meta: http.AssertionMeta{
|
||||
TestCaseName: "case1: disable gzip output",
|
||||
TargetBackend: "web-backend",
|
||||
TargetNamespace: "higress-conformance-infra",
|
||||
},
|
||||
Request: http.AssertionRequest{
|
||||
ActualRequest: http.Request{
|
||||
Host: "foo.com",
|
||||
Path: "/foo",
|
||||
Method: "GET",
|
||||
Headers: map[string]string{
|
||||
"Accept-Encoding": "*",
|
||||
},
|
||||
},
|
||||
},
|
||||
Response: http.AssertionResponse{
|
||||
ExpectedResponseNoRequest: true,
|
||||
ExpectedResponse: http.Response{
|
||||
StatusCode: 200,
|
||||
AbsentHeaders: []string{"content-encoding"},
|
||||
},
|
||||
},
|
||||
},
|
||||
envoyAssertion: envoy.Assertion{
|
||||
Path: "configs.#.dynamic_listeners.#.active_state.listener.filter_chains",
|
||||
TargetNamespace: "higress-system",
|
||||
CheckType: envoy.CheckTypeNotExist,
|
||||
ExpectEnvoyConfig: map[string]interface{}{
|
||||
"memory_level": 5,
|
||||
"compression_level": "COMPRESSION_LEVEL_9",
|
||||
"window_bits": 12,
|
||||
"min_content_length": 1024,
|
||||
"disable_on_etag_header": true,
|
||||
"content_type": []interface{}{
|
||||
"text/html",
|
||||
"text/css",
|
||||
"text/plain",
|
||||
"text/xml",
|
||||
"application/json",
|
||||
"application/javascript",
|
||||
"application/xhtml+xml",
|
||||
"image/svg+xml",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
higressConfig: &configmap.HigressConfig{
|
||||
Gzip: &configmap.Gzip{
|
||||
Enable: true,
|
||||
MinContentLength: 100,
|
||||
ContentType: []string{"text/html", "text/css", "text/plain", "text/xml", "application/json", "application/javascript", "application/xhtml+xml", "image/svg+xml"},
|
||||
DisableOnEtagHeader: true,
|
||||
MemoryLevel: 5,
|
||||
WindowBits: 12,
|
||||
ChunkSize: 4096,
|
||||
CompressionLevel: "BEST_COMPRESSION",
|
||||
CompressionStrategy: "DEFAULT_STRATEGY",
|
||||
},
|
||||
},
|
||||
httpAssert: http.Assertion{
|
||||
Meta: http.AssertionMeta{
|
||||
TestCaseName: "case2: enable gzip output",
|
||||
TargetBackend: "web-backend",
|
||||
TargetNamespace: "higress-conformance-infra",
|
||||
},
|
||||
Request: http.AssertionRequest{
|
||||
ActualRequest: http.Request{
|
||||
Host: "foo.com",
|
||||
Path: "/foo",
|
||||
Method: "GET",
|
||||
Headers: map[string]string{
|
||||
"Accept-Encoding": "*",
|
||||
},
|
||||
},
|
||||
},
|
||||
Response: http.AssertionResponse{
|
||||
ExpectedResponseNoRequest: true,
|
||||
ExpectedResponse: http.Response{
|
||||
StatusCode: 200,
|
||||
},
|
||||
AdditionalResponseHeaders: map[string]string{"content-encoding": "gzip"},
|
||||
},
|
||||
},
|
||||
envoyAssertion: envoy.Assertion{
|
||||
Path: "configs.#.dynamic_listeners.#.active_state.listener.filter_chains",
|
||||
TargetNamespace: "higress-system",
|
||||
CheckType: envoy.CheckTypeExist,
|
||||
ExpectEnvoyConfig: map[string]interface{}{
|
||||
"name": "envoy.filters.network.http_connection_manager",
|
||||
"@type": "type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager",
|
||||
"stat_prefix": "outbound_0.0.0.0_80",
|
||||
"memory_level": 5,
|
||||
"compression_level": "COMPRESSION_LEVEL_9",
|
||||
"window_bits": 12,
|
||||
"min_content_length": 100,
|
||||
"disable_on_etag_header": true,
|
||||
"content_type": []interface{}{
|
||||
"text/html",
|
||||
"text/css",
|
||||
"text/plain",
|
||||
"text/xml",
|
||||
"application/json",
|
||||
"application/javascript",
|
||||
"application/xhtml+xml",
|
||||
"image/svg+xml",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
higressConfig: &configmap.HigressConfig{
|
||||
Gzip: &configmap.Gzip{
|
||||
Enable: true,
|
||||
MinContentLength: 4096,
|
||||
ContentType: []string{"text/html", "text/css", "text/plain", "text/xml", "application/json", "application/javascript", "application/xhtml+xml", "image/svg+xml"},
|
||||
DisableOnEtagHeader: true,
|
||||
MemoryLevel: 5,
|
||||
WindowBits: 12,
|
||||
ChunkSize: 4096,
|
||||
CompressionLevel: "BEST_COMPRESSION",
|
||||
CompressionStrategy: "DEFAULT_STRATEGY",
|
||||
},
|
||||
},
|
||||
httpAssert: http.Assertion{
|
||||
Meta: http.AssertionMeta{
|
||||
TestCaseName: "case3: disable gzip output because content length less hhan 4096 ",
|
||||
TargetBackend: "web-backend",
|
||||
TargetNamespace: "higress-conformance-infra",
|
||||
},
|
||||
Request: http.AssertionRequest{
|
||||
ActualRequest: http.Request{
|
||||
Host: "foo.com",
|
||||
Path: "/foo",
|
||||
Method: "GET",
|
||||
Headers: map[string]string{
|
||||
"Accept-Encoding": "*",
|
||||
},
|
||||
},
|
||||
},
|
||||
Response: http.AssertionResponse{
|
||||
ExpectedResponseNoRequest: true,
|
||||
ExpectedResponse: http.Response{
|
||||
StatusCode: 200,
|
||||
AbsentHeaders: []string{"content-encoding"},
|
||||
},
|
||||
},
|
||||
},
|
||||
envoyAssertion: envoy.Assertion{
|
||||
Path: "configs.#.dynamic_listeners.#.active_state.listener.filter_chains",
|
||||
TargetNamespace: "higress-system",
|
||||
CheckType: envoy.CheckTypeExist,
|
||||
ExpectEnvoyConfig: map[string]interface{}{
|
||||
"name": "envoy.filters.network.http_connection_manager",
|
||||
"@type": "type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager",
|
||||
"stat_prefix": "outbound_0.0.0.0_80",
|
||||
"memory_level": 5,
|
||||
"compression_level": "COMPRESSION_LEVEL_9",
|
||||
"window_bits": 12,
|
||||
"min_content_length": 4096,
|
||||
"disable_on_etag_header": true,
|
||||
"content_type": []interface{}{
|
||||
"text/html",
|
||||
"text/css",
|
||||
"text/plain",
|
||||
"text/xml",
|
||||
"application/json",
|
||||
"application/javascript",
|
||||
"application/xhtml+xml",
|
||||
"image/svg+xml",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
higressConfig: &configmap.HigressConfig{
|
||||
Gzip: &configmap.Gzip{
|
||||
Enable: true,
|
||||
MinContentLength: 100,
|
||||
ContentType: []string{"text/html", "text/css", "text/plain", "text/xml", "application/javascript", "application/xhtml+xml", "image/svg+xml"},
|
||||
DisableOnEtagHeader: true,
|
||||
MemoryLevel: 5,
|
||||
WindowBits: 12,
|
||||
ChunkSize: 4096,
|
||||
CompressionLevel: "BEST_COMPRESSION",
|
||||
CompressionStrategy: "DEFAULT_STRATEGY",
|
||||
},
|
||||
},
|
||||
httpAssert: http.Assertion{
|
||||
Meta: http.AssertionMeta{
|
||||
TestCaseName: "case4: disable gzip output because application/json missed in content types ",
|
||||
TargetBackend: "web-backend",
|
||||
TargetNamespace: "higress-conformance-infra",
|
||||
},
|
||||
Request: http.AssertionRequest{
|
||||
ActualRequest: http.Request{
|
||||
Host: "foo.com",
|
||||
Path: "/foo",
|
||||
Method: "GET",
|
||||
Headers: map[string]string{
|
||||
"Accept-Encoding": "*",
|
||||
},
|
||||
},
|
||||
},
|
||||
Response: http.AssertionResponse{
|
||||
ExpectedResponseNoRequest: true,
|
||||
ExpectedResponse: http.Response{
|
||||
StatusCode: 200,
|
||||
AbsentHeaders: []string{"content-encoding"},
|
||||
},
|
||||
},
|
||||
},
|
||||
envoyAssertion: envoy.Assertion{
|
||||
Path: "configs.#.dynamic_listeners.#.active_state.listener.filter_chains",
|
||||
TargetNamespace: "higress-system",
|
||||
CheckType: envoy.CheckTypeExist,
|
||||
ExpectEnvoyConfig: map[string]interface{}{
|
||||
"name": "envoy.filters.network.http_connection_manager",
|
||||
"@type": "type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager",
|
||||
"stat_prefix": "outbound_0.0.0.0_80",
|
||||
"memory_level": 5,
|
||||
"compression_level": "COMPRESSION_LEVEL_9",
|
||||
"window_bits": 12,
|
||||
"min_content_length": 100,
|
||||
"disable_on_etag_header": true,
|
||||
"content_type": []interface{}{
|
||||
"text/html",
|
||||
"text/css",
|
||||
"text/plain",
|
||||
"text/xml",
|
||||
"application/javascript",
|
||||
"application/xhtml+xml",
|
||||
"image/svg+xml",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
var ConfigmapGzip = suite.ConformanceTest{
|
||||
@@ -33,171 +294,9 @@ var ConfigmapGzip = suite.ConformanceTest{
|
||||
Manifests: []string{"tests/configmap-gzip.yaml"},
|
||||
Features: []suite.SupportedFeature{suite.HTTPConformanceFeature},
|
||||
Test: func(t *testing.T, suite *suite.ConformanceTestSuite) {
|
||||
testcases := []struct {
|
||||
higressConfig *configmap.HigressConfig
|
||||
httpAssert http.Assertion
|
||||
}{
|
||||
{
|
||||
higressConfig: &configmap.HigressConfig{
|
||||
Gzip: &configmap.Gzip{
|
||||
Enable: false,
|
||||
MinContentLength: 1024,
|
||||
ContentType: []string{"text/html", "text/css", "text/plain", "text/xml", "application/json", "application/javascript", "application/xhtml+xml", "image/svg+xml"},
|
||||
DisableOnEtagHeader: true,
|
||||
MemoryLevel: 5,
|
||||
WindowBits: 12,
|
||||
ChunkSize: 4096,
|
||||
CompressionLevel: "BEST_COMPRESSION",
|
||||
CompressionStrategy: "DEFAULT_STRATEGY",
|
||||
},
|
||||
},
|
||||
httpAssert: http.Assertion{
|
||||
Meta: http.AssertionMeta{
|
||||
TestCaseName: "case1: disable gzip output",
|
||||
TargetBackend: "web-backend",
|
||||
TargetNamespace: "higress-conformance-infra",
|
||||
},
|
||||
Request: http.AssertionRequest{
|
||||
ActualRequest: http.Request{
|
||||
Host: "foo.com",
|
||||
Path: "/foo",
|
||||
Method: "GET",
|
||||
Headers: map[string]string{
|
||||
"Accept-Encoding": "*",
|
||||
},
|
||||
},
|
||||
},
|
||||
Response: http.AssertionResponse{
|
||||
ExpectedResponseNoRequest: true,
|
||||
ExpectedResponse: http.Response{
|
||||
StatusCode: 200,
|
||||
AbsentHeaders: []string{"content-encoding"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
higressConfig: &configmap.HigressConfig{
|
||||
Gzip: &configmap.Gzip{
|
||||
Enable: true,
|
||||
MinContentLength: 100,
|
||||
ContentType: []string{"text/html", "text/css", "text/plain", "text/xml", "application/json", "application/javascript", "application/xhtml+xml", "image/svg+xml"},
|
||||
DisableOnEtagHeader: true,
|
||||
MemoryLevel: 5,
|
||||
WindowBits: 12,
|
||||
ChunkSize: 4096,
|
||||
CompressionLevel: "BEST_COMPRESSION",
|
||||
CompressionStrategy: "DEFAULT_STRATEGY",
|
||||
},
|
||||
},
|
||||
httpAssert: http.Assertion{
|
||||
Meta: http.AssertionMeta{
|
||||
TestCaseName: "case2: enable gzip output",
|
||||
TargetBackend: "web-backend",
|
||||
TargetNamespace: "higress-conformance-infra",
|
||||
},
|
||||
Request: http.AssertionRequest{
|
||||
ActualRequest: http.Request{
|
||||
Host: "foo.com",
|
||||
Path: "/foo",
|
||||
Method: "GET",
|
||||
Headers: map[string]string{
|
||||
"Accept-Encoding": "*",
|
||||
},
|
||||
},
|
||||
},
|
||||
Response: http.AssertionResponse{
|
||||
ExpectedResponseNoRequest: true,
|
||||
ExpectedResponse: http.Response{
|
||||
StatusCode: 200,
|
||||
},
|
||||
AdditionalResponseHeaders: map[string]string{"content-encoding": "gzip"},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
higressConfig: &configmap.HigressConfig{
|
||||
Gzip: &configmap.Gzip{
|
||||
Enable: true,
|
||||
MinContentLength: 4096,
|
||||
ContentType: []string{"text/html", "text/css", "text/plain", "text/xml", "application/json", "application/javascript", "application/xhtml+xml", "image/svg+xml"},
|
||||
DisableOnEtagHeader: true,
|
||||
MemoryLevel: 5,
|
||||
WindowBits: 12,
|
||||
ChunkSize: 4096,
|
||||
CompressionLevel: "BEST_COMPRESSION",
|
||||
CompressionStrategy: "DEFAULT_STRATEGY",
|
||||
},
|
||||
},
|
||||
httpAssert: http.Assertion{
|
||||
Meta: http.AssertionMeta{
|
||||
TestCaseName: "case3: disable gzip output because content length less hhan 4096 ",
|
||||
TargetBackend: "web-backend",
|
||||
TargetNamespace: "higress-conformance-infra",
|
||||
},
|
||||
Request: http.AssertionRequest{
|
||||
ActualRequest: http.Request{
|
||||
Host: "foo.com",
|
||||
Path: "/foo",
|
||||
Method: "GET",
|
||||
Headers: map[string]string{
|
||||
"Accept-Encoding": "*",
|
||||
},
|
||||
},
|
||||
},
|
||||
Response: http.AssertionResponse{
|
||||
ExpectedResponseNoRequest: true,
|
||||
ExpectedResponse: http.Response{
|
||||
StatusCode: 200,
|
||||
AbsentHeaders: []string{"content-encoding"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
higressConfig: &configmap.HigressConfig{
|
||||
Gzip: &configmap.Gzip{
|
||||
Enable: true,
|
||||
MinContentLength: 100,
|
||||
ContentType: []string{"text/html", "text/css", "text/plain", "text/xml", "application/javascript", "application/xhtml+xml", "image/svg+xml"},
|
||||
DisableOnEtagHeader: true,
|
||||
MemoryLevel: 5,
|
||||
WindowBits: 12,
|
||||
ChunkSize: 4096,
|
||||
CompressionLevel: "BEST_COMPRESSION",
|
||||
CompressionStrategy: "DEFAULT_STRATEGY",
|
||||
},
|
||||
},
|
||||
httpAssert: http.Assertion{
|
||||
Meta: http.AssertionMeta{
|
||||
TestCaseName: "case4: disable gzip output because application/json missed in content types ",
|
||||
TargetBackend: "web-backend",
|
||||
TargetNamespace: "higress-conformance-infra",
|
||||
},
|
||||
Request: http.AssertionRequest{
|
||||
ActualRequest: http.Request{
|
||||
Host: "foo.com",
|
||||
Path: "/foo",
|
||||
Method: "GET",
|
||||
Headers: map[string]string{
|
||||
"Accept-Encoding": "*",
|
||||
},
|
||||
},
|
||||
},
|
||||
Response: http.AssertionResponse{
|
||||
ExpectedResponseNoRequest: true,
|
||||
ExpectedResponse: http.Response{
|
||||
StatusCode: 200,
|
||||
AbsentHeaders: []string{"content-encoding"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
t.Run("Configmap Gzip", func(t *testing.T) {
|
||||
for _, testcase := range testcases {
|
||||
err := kubernetes.ApplyConfigmapDataWithYaml(suite.Client, "higress-system", "higress-config", "higress", testcase.higressConfig)
|
||||
for _, testcase := range testCases {
|
||||
err := kubernetes.ApplyConfigmapDataWithYaml(t, suite.Client, "higress-system", "higress-config", "higress", testcase.higressConfig)
|
||||
if err != nil {
|
||||
t.Fatalf("can't apply conifgmap %s in namespace %s for data key %s", "higress-config", "higress-system", "higress")
|
||||
}
|
||||
@@ -206,3 +305,22 @@ var ConfigmapGzip = suite.ConformanceTest{
|
||||
})
|
||||
},
|
||||
}
|
||||
|
||||
var ConfigMapGzipEnvoy = suite.ConformanceTest{
|
||||
ShortName: "ConfigMapGzipEnvoy",
|
||||
Description: "The Envoy config should contain gzip config",
|
||||
Manifests: []string{"tests/configmap-gzip.yaml"},
|
||||
Features: []suite.SupportedFeature{suite.EnvoyConfigConformanceFeature},
|
||||
Test: func(t *testing.T, suite *suite.ConformanceTestSuite) {
|
||||
t.Run("ConfigMap Gzip Envoy", func(t *testing.T) {
|
||||
for _, testcase := range testCases {
|
||||
// apply config
|
||||
err := kubernetes.ApplyConfigmapDataWithYaml(t, suite.Client, "higress-system", "higress-config", "higress", testcase.higressConfig)
|
||||
if err != nil {
|
||||
t.Fatalf("can't apply conifgmap %s in namespace %s for data key %s", "higress-config", "higress-system", "higress")
|
||||
}
|
||||
envoy.AssertEnvoyConfig(t, suite.TimeoutConfig, testcase.envoyAssertion)
|
||||
}
|
||||
})
|
||||
},
|
||||
}
|
||||
|
||||
@@ -29,4 +29,5 @@ spec:
|
||||
service:
|
||||
name: infra-backend-v3
|
||||
port:
|
||||
number: 8080
|
||||
number: 8080
|
||||
|
||||
|
||||
287
test/e2e/conformance/utils/envoy/envoy.go
Normal file
287
test/e2e/conformance/utils/envoy/envoy.go
Normal file
@@ -0,0 +1,287 @@
|
||||
/*
|
||||
Copyright 2022 The Kubernetes Authors.
|
||||
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 envoy
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/alibaba/higress/cmd/hgctl/config"
|
||||
cfg "github.com/alibaba/higress/test/e2e/conformance/utils/config"
|
||||
"github.com/tidwall/gjson"
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
)
|
||||
|
||||
type CheckType string
|
||||
|
||||
const (
|
||||
// CheckTypeMatch checks if the actual value matches the expected value.
|
||||
CheckTypeMatch CheckType = "match"
|
||||
// CheckTypeExist checks if the actual value exists.
|
||||
CheckTypeExist CheckType = "exist"
|
||||
// CheckTypeNotExist checks if the actual value does not exist.
|
||||
CheckTypeNotExist CheckType = "notexist"
|
||||
|
||||
// defaultSuccessThreshold is the default number of times the assertion must succeed in a row.
|
||||
defaultSuccessThreshold = 3
|
||||
)
|
||||
|
||||
// Assertion defines the assertion to be made on the Envoy config.
|
||||
// TODO: It can support localization judgment so that this configuration check function will be more universal.
|
||||
// TODO: Can be used for general e2e tests, rather than just envoy filter scenarios.
|
||||
type Assertion struct {
|
||||
// Path is the path of gjson to the value to be asserted.
|
||||
Path string
|
||||
// CheckType is the type of assertion to be made.
|
||||
CheckType CheckType
|
||||
// ExpectEnvoyConfig is the expected value of the Envoy config.
|
||||
ExpectEnvoyConfig map[string]interface{}
|
||||
// TargetNamespace is the namespace of the Envoy pod.
|
||||
TargetNamespace string
|
||||
}
|
||||
|
||||
// AssertEnvoyConfig asserts the Envoy config.
|
||||
func AssertEnvoyConfig(t *testing.T, timeoutConfig cfg.TimeoutConfig, expected Assertion) {
|
||||
options := config.NewDefaultGetEnvoyConfigOptions()
|
||||
options.PodNamespace = expected.TargetNamespace
|
||||
waitForEnvoyConfig(t, timeoutConfig, options, expected)
|
||||
}
|
||||
|
||||
// waitForEnvoyConfig waits for the Envoy config to be ready and asserts it.
|
||||
func waitForEnvoyConfig(t *testing.T, timeoutConfig cfg.TimeoutConfig, options *config.GetEnvoyConfigOptions, expected Assertion) {
|
||||
awaitConvergence(t, defaultSuccessThreshold, timeoutConfig.MaxTimeToConsistency, func(elapsed time.Duration) bool {
|
||||
allEnvoyConfig := ""
|
||||
err := wait.Poll(1*time.Second, 10*time.Second, func() (bool, error) {
|
||||
out, err := config.GetEnvoyConfig(options)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
allEnvoyConfig = string(out)
|
||||
return true, nil
|
||||
})
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
switch expected.CheckType {
|
||||
case CheckTypeMatch:
|
||||
err = assertEnvoyConfigMatch(t, allEnvoyConfig, expected)
|
||||
case CheckTypeExist:
|
||||
err = assertEnvoyConfigExist(t, allEnvoyConfig, expected)
|
||||
case CheckTypeNotExist:
|
||||
err = assertEnvoyConfigNotExist(t, allEnvoyConfig, expected)
|
||||
default:
|
||||
err = fmt.Errorf("unsupported check type %s", expected.CheckType)
|
||||
}
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
})
|
||||
t.Logf("✅ Envoy config checked")
|
||||
}
|
||||
|
||||
// assertEnvoyConfigNotExist asserts the Envoy config does not exist.
|
||||
func assertEnvoyConfigNotExist(t *testing.T, envoyConfig string, expected Assertion) error {
|
||||
result := gjson.Get(envoyConfig, expected.Path).Value()
|
||||
if result == nil {
|
||||
return nil
|
||||
}
|
||||
if !findMustNotExist(t, result, expected.ExpectEnvoyConfig) {
|
||||
return fmt.Errorf("the expected value %s exists in path '%s'", expected.ExpectEnvoyConfig, expected.Path)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// assertEnvoyConfigExist asserts the Envoy config exists.
|
||||
func assertEnvoyConfigExist(t *testing.T, envoyConfig string, expected Assertion) error {
|
||||
result := gjson.Get(envoyConfig, expected.Path).Value()
|
||||
if result == nil {
|
||||
return fmt.Errorf("failed to get value from path '%s'", expected.Path)
|
||||
}
|
||||
if !findMustExist(t, result, expected.ExpectEnvoyConfig) {
|
||||
return fmt.Errorf("the expected value %s does not exist in path '%s'", expected.ExpectEnvoyConfig, expected.Path)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// assertEnvoyConfigMatch asserts the Envoy config matches the expected value.
|
||||
func assertEnvoyConfigMatch(t *testing.T, envoyConfig string, expected Assertion) error {
|
||||
result := gjson.Get(envoyConfig, expected.Path).Value()
|
||||
if result == nil {
|
||||
return fmt.Errorf("failed to get value from path '%s'", expected.Path)
|
||||
}
|
||||
if !match(t, result, expected.ExpectEnvoyConfig) {
|
||||
return fmt.Errorf("failed to match value from path '%s'", expected.Path)
|
||||
}
|
||||
t.Logf("✅ Matched value %s in path '%s'", expected.ExpectEnvoyConfig, expected.Path)
|
||||
return nil
|
||||
}
|
||||
|
||||
// awaitConvergence runs the given function until it returns 'true' `threshold` times in a row.
|
||||
// Each failed attempt has a 1s delay; successful attempts have no delay.
|
||||
func awaitConvergence(t *testing.T, threshold int, maxTimeToConsistency time.Duration, fn func(elapsed time.Duration) bool) {
|
||||
successes := 0
|
||||
attempts := 0
|
||||
start := time.Now()
|
||||
to := time.After(maxTimeToConsistency)
|
||||
delay := time.Second
|
||||
for {
|
||||
select {
|
||||
case <-to:
|
||||
t.Fatalf("timeout while waiting after %d attempts", attempts)
|
||||
default:
|
||||
}
|
||||
|
||||
completed := fn(time.Now().Sub(start))
|
||||
attempts++
|
||||
if completed {
|
||||
successes++
|
||||
if successes >= threshold {
|
||||
return
|
||||
}
|
||||
// Skip delay if we have a success
|
||||
continue
|
||||
}
|
||||
|
||||
successes = 0
|
||||
select {
|
||||
// Capture the overall timeout
|
||||
case <-to:
|
||||
t.Fatalf("timeout while waiting after %d attempts, %d/%d sucessess", attempts, successes, threshold)
|
||||
// And the per-try delay
|
||||
case <-time.After(delay):
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// match
|
||||
// 1. interface{} is a slice: if one of the slice elements matches, the assertion passes
|
||||
// Notice: can recursively find slices
|
||||
// 2. interface{} is a map: if all the map elements match, the assertion passes
|
||||
// 3. interface{} is a field: if the field matches, the assertion passes
|
||||
func match(t *testing.T, actual interface{}, expected map[string]interface{}) bool {
|
||||
reflectValue := reflect.ValueOf(actual)
|
||||
kind := reflectValue.Kind()
|
||||
switch kind {
|
||||
case reflect.Slice:
|
||||
actualValueSlice := actual.([]interface{})
|
||||
for _, v := range actualValueSlice {
|
||||
if match(t, v, expected) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
case reflect.Map:
|
||||
actualValueMap := actual.(map[string]interface{})
|
||||
for key, expectValue := range expected {
|
||||
actualValue, ok := actualValueMap[key]
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
if !reflect.DeepEqual(actualValue, expectValue) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
default:
|
||||
return reflect.DeepEqual(actual, expected)
|
||||
}
|
||||
}
|
||||
|
||||
// findMustExist finds the value of the given path in the given Envoy config.
|
||||
func findMustExist(t *testing.T, actual interface{}, expected map[string]interface{}) bool {
|
||||
for key, expectValue := range expected {
|
||||
// If the key does not exist, the assertion fails.
|
||||
t.Logf("🔍 Finding key %s", key)
|
||||
if !findKey(actual, key, expectValue) {
|
||||
t.Logf("❌ Not found key %s", key)
|
||||
return false
|
||||
}
|
||||
t.Logf("✅ Found key %s", key)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// findMustNotExist finds the value of the given path in the given Envoy config.
|
||||
func findMustNotExist(t *testing.T, actual interface{}, expected map[string]interface{}) bool {
|
||||
for key, expectValue := range expected {
|
||||
// If the key exists, the assertion fails.
|
||||
t.Logf("🔍 Finding key %s", key)
|
||||
if findKey(actual, key, expectValue) {
|
||||
t.Logf("❌ Found key %s", key)
|
||||
return false
|
||||
}
|
||||
t.Logf("✅ Not found key %s", key)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// findKey finds the value of the given key in the given Envoy config.
|
||||
func findKey(actual interface{}, key string, expectValue interface{}) bool {
|
||||
reflectValue := reflect.ValueOf(actual)
|
||||
kind := reflectValue.Kind()
|
||||
switch kind {
|
||||
case reflect.Slice:
|
||||
actualValueSlice := actual.([]interface{})
|
||||
for _, v := range actualValueSlice {
|
||||
if findKey(v, key, expectValue) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
case reflect.Map:
|
||||
actualValueMap := actual.(map[string]interface{})
|
||||
for actualKey, actualValue := range actualValueMap {
|
||||
if actualKey == key && reflect.DeepEqual(convertType(actualValue, expectValue), expectValue) {
|
||||
return true
|
||||
}
|
||||
if findKey(actualValue, key, expectValue) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
default:
|
||||
if reflectValue.String() == key && reflect.DeepEqual(convertType(actual, expectValue), expectValue) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// convertType converts the type of the given value to the type of the given target value.
|
||||
func convertType(value interface{}, targetType interface{}) interface{} {
|
||||
targetTypeValue := reflect.ValueOf(targetType)
|
||||
targetTypeKind := targetTypeValue.Kind()
|
||||
|
||||
switch targetTypeKind {
|
||||
case reflect.Int:
|
||||
switch value.(type) {
|
||||
case int:
|
||||
return value
|
||||
case float64:
|
||||
return int(value.(float64))
|
||||
}
|
||||
case reflect.Float64:
|
||||
switch value.(type) {
|
||||
case int:
|
||||
return float64(value.(int))
|
||||
case float64:
|
||||
return value
|
||||
}
|
||||
}
|
||||
|
||||
return value
|
||||
}
|
||||
462
test/e2e/conformance/utils/envoy/envoy_test.go
Normal file
462
test/e2e/conformance/utils/envoy/envoy_test.go
Normal file
@@ -0,0 +1,462 @@
|
||||
/*
|
||||
Copyright 2022 The Kubernetes Authors.
|
||||
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 envoy
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func Test_match(t *testing.T) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
actual interface{}
|
||||
expected map[string]interface{}
|
||||
expectResult bool
|
||||
}{
|
||||
{
|
||||
name: "case 1",
|
||||
actual: []interface{}{
|
||||
map[string]interface{}{
|
||||
"foo": "bar",
|
||||
},
|
||||
map[string]interface{}{
|
||||
"foo": "baz",
|
||||
},
|
||||
},
|
||||
expected: map[string]interface{}{
|
||||
"foo": "bar",
|
||||
},
|
||||
expectResult: true,
|
||||
},
|
||||
{
|
||||
name: "case 2",
|
||||
actual: []interface{}{
|
||||
map[string]interface{}{
|
||||
"foo": "bar",
|
||||
},
|
||||
map[string]interface{}{
|
||||
"foo": "baz",
|
||||
},
|
||||
},
|
||||
expected: map[string]interface{}{
|
||||
"foo": "bay",
|
||||
},
|
||||
expectResult: false,
|
||||
},
|
||||
{
|
||||
name: "case 3",
|
||||
actual: map[string]interface{}{
|
||||
"foo": "bar",
|
||||
"bar": "baz",
|
||||
"baz": "bay",
|
||||
},
|
||||
expected: map[string]interface{}{
|
||||
"foo": "bar",
|
||||
},
|
||||
expectResult: true,
|
||||
},
|
||||
{
|
||||
name: "case 4",
|
||||
actual: map[string]interface{}{
|
||||
"foo": "bar",
|
||||
},
|
||||
expected: map[string]interface{}{
|
||||
"foo": "bar",
|
||||
},
|
||||
expectResult: true,
|
||||
},
|
||||
{
|
||||
name: "case 5",
|
||||
actual: map[string]interface{}{
|
||||
"foo": "bar",
|
||||
},
|
||||
expected: map[string]interface{}{
|
||||
"foo": "baz",
|
||||
},
|
||||
expectResult: false,
|
||||
},
|
||||
{
|
||||
name: "case 6",
|
||||
actual: []interface{}{
|
||||
[]interface{}{
|
||||
map[string]interface{}{
|
||||
"foo": "bar",
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: map[string]interface{}{
|
||||
"foo": "bar",
|
||||
},
|
||||
expectResult: true,
|
||||
},
|
||||
{
|
||||
name: "case 7",
|
||||
actual: []interface{}{
|
||||
map[string]interface{}{
|
||||
"foo": "bar",
|
||||
},
|
||||
[]interface{}{
|
||||
map[string]interface{}{
|
||||
"foo": "baz",
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: map[string]interface{}{
|
||||
"foo": "baz",
|
||||
},
|
||||
expectResult: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, testCase := range testCases {
|
||||
t.Run(testCase.name, func(t *testing.T) {
|
||||
result := match(t, testCase.actual, testCase.expected)
|
||||
if result != testCase.expectResult {
|
||||
t.Errorf("expected %v, got %v", testCase.expectResult, result)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_findMustExist(t *testing.T) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
actual interface{}
|
||||
expected map[string]interface{}
|
||||
expectResult bool
|
||||
}{
|
||||
{
|
||||
name: "case 1",
|
||||
actual: []interface{}{
|
||||
map[string]interface{}{
|
||||
"foo": "bar",
|
||||
},
|
||||
},
|
||||
expected: map[string]interface{}{
|
||||
"foo": "bar",
|
||||
},
|
||||
expectResult: true,
|
||||
},
|
||||
{
|
||||
name: "case 2",
|
||||
actual: []interface{}{
|
||||
map[string]interface{}{
|
||||
"foo": "bar",
|
||||
},
|
||||
},
|
||||
expected: map[string]interface{}{
|
||||
"foo": "baz",
|
||||
},
|
||||
expectResult: false,
|
||||
},
|
||||
{
|
||||
name: "case 3",
|
||||
actual: map[string]interface{}{
|
||||
"foo": "bar",
|
||||
"bar": "baz",
|
||||
"baz": "bay",
|
||||
},
|
||||
expected: map[string]interface{}{
|
||||
"foo": "bar",
|
||||
},
|
||||
expectResult: true,
|
||||
},
|
||||
{
|
||||
name: "case 4",
|
||||
actual: map[string]interface{}{
|
||||
"foo": "bar",
|
||||
},
|
||||
expected: map[string]interface{}{
|
||||
"foo": "baz",
|
||||
},
|
||||
expectResult: false,
|
||||
},
|
||||
{
|
||||
name: "case 5",
|
||||
actual: []interface{}{
|
||||
[]interface{}{
|
||||
map[string]interface{}{
|
||||
"foo": "bar",
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: map[string]interface{}{
|
||||
"foo": "bar",
|
||||
},
|
||||
expectResult: true,
|
||||
},
|
||||
{
|
||||
name: "case 6",
|
||||
actual: []interface{}{
|
||||
map[string]interface{}{
|
||||
"foo": "bar",
|
||||
},
|
||||
[]interface{}{
|
||||
map[string]interface{}{
|
||||
"foo": "baz",
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: map[string]interface{}{
|
||||
"foo": "baz",
|
||||
},
|
||||
expectResult: true,
|
||||
},
|
||||
{
|
||||
name: "case 7",
|
||||
actual: []interface{}{
|
||||
map[string]interface{}{
|
||||
"foo": "bar",
|
||||
},
|
||||
[]interface{}{
|
||||
map[string]interface{}{
|
||||
"test": "baz",
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: map[string]interface{}{
|
||||
"foo": "bar",
|
||||
"test": "baz",
|
||||
},
|
||||
expectResult: true,
|
||||
},
|
||||
{
|
||||
name: "case 8",
|
||||
actual: []interface{}{
|
||||
map[string]interface{}{
|
||||
"foo": "bar",
|
||||
"test": "baz",
|
||||
},
|
||||
[]interface{}{
|
||||
map[string]interface{}{
|
||||
"foo": "baz",
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: map[string]interface{}{
|
||||
"foo": "baz",
|
||||
"test": "baz",
|
||||
},
|
||||
expectResult: true,
|
||||
},
|
||||
{
|
||||
name: "case 9",
|
||||
actual: []interface{}{
|
||||
map[string]interface{}{
|
||||
"foo": "bar",
|
||||
},
|
||||
[]interface{}{
|
||||
[]interface{}{
|
||||
map[string]interface{}{
|
||||
"foo": "baz",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: map[string]interface{}{
|
||||
"foo": "baz",
|
||||
},
|
||||
expectResult: true,
|
||||
},
|
||||
{
|
||||
name: "case 9",
|
||||
actual: []interface{}{
|
||||
map[string]interface{}{
|
||||
"foo": "bar",
|
||||
},
|
||||
[]interface{}{
|
||||
[]interface{}{
|
||||
map[string]interface{}{
|
||||
"foo": "baz",
|
||||
},
|
||||
},
|
||||
},
|
||||
map[string]interface{}{
|
||||
"content": []interface{}{
|
||||
"one",
|
||||
"two",
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: map[string]interface{}{
|
||||
"foo": "baz",
|
||||
"content": []interface{}{
|
||||
"one",
|
||||
"two",
|
||||
},
|
||||
},
|
||||
expectResult: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, testCase := range testCases {
|
||||
t.Run(testCase.name, func(t *testing.T) {
|
||||
result := findMustExist(t, testCase.actual, testCase.expected)
|
||||
if result != testCase.expectResult {
|
||||
t.Errorf("expected %v, got %v", testCase.expectResult, result)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_findMustNotExist(t *testing.T) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
actual interface{}
|
||||
expected map[string]interface{}
|
||||
expectResult bool
|
||||
}{
|
||||
{
|
||||
name: "case 1",
|
||||
actual: []interface{}{
|
||||
map[string]interface{}{
|
||||
"foo": "bar",
|
||||
},
|
||||
},
|
||||
expected: map[string]interface{}{
|
||||
"foo": "bar",
|
||||
},
|
||||
expectResult: false,
|
||||
},
|
||||
{
|
||||
name: "case 2",
|
||||
actual: []interface{}{
|
||||
map[string]interface{}{
|
||||
"foo": "bar",
|
||||
},
|
||||
},
|
||||
expected: map[string]interface{}{
|
||||
"foo": "baz",
|
||||
},
|
||||
expectResult: true,
|
||||
},
|
||||
{
|
||||
name: "case 3",
|
||||
actual: map[string]interface{}{
|
||||
"foo": "bar",
|
||||
"bar": "baz",
|
||||
"baz": "bay",
|
||||
},
|
||||
expected: map[string]interface{}{
|
||||
"foo": "bar",
|
||||
},
|
||||
expectResult: false,
|
||||
},
|
||||
{
|
||||
name: "case 4",
|
||||
actual: map[string]interface{}{
|
||||
"foo": "bar",
|
||||
},
|
||||
expected: map[string]interface{}{
|
||||
"foo": "baz",
|
||||
},
|
||||
expectResult: true,
|
||||
},
|
||||
{
|
||||
name: "case 5",
|
||||
actual: []interface{}{
|
||||
[]interface{}{
|
||||
map[string]interface{}{
|
||||
"foo": "bar",
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: map[string]interface{}{
|
||||
"foo": "bar",
|
||||
},
|
||||
expectResult: false,
|
||||
},
|
||||
{
|
||||
name: "case 6",
|
||||
actual: []interface{}{
|
||||
map[string]interface{}{
|
||||
"foo": "bar",
|
||||
},
|
||||
[]interface{}{
|
||||
map[string]interface{}{
|
||||
"foo": "baz",
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: map[string]interface{}{
|
||||
"foo": "baz",
|
||||
},
|
||||
expectResult: false,
|
||||
},
|
||||
{
|
||||
name: "case 7",
|
||||
actual: []interface{}{
|
||||
map[string]interface{}{
|
||||
"foo": "bar",
|
||||
},
|
||||
[]interface{}{
|
||||
map[string]interface{}{
|
||||
"test": "baz",
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: map[string]interface{}{
|
||||
"foo": "bar",
|
||||
},
|
||||
expectResult: false,
|
||||
},
|
||||
{
|
||||
name: "case 8",
|
||||
actual: []interface{}{
|
||||
map[string]interface{}{
|
||||
"foo": "bar",
|
||||
"test": "baz",
|
||||
},
|
||||
[]interface{}{
|
||||
map[string]interface{}{
|
||||
"foo": "baz",
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: map[string]interface{}{
|
||||
"foo": "baz",
|
||||
"test": "baz",
|
||||
},
|
||||
expectResult: false,
|
||||
},
|
||||
{
|
||||
name: "case 9",
|
||||
actual: []interface{}{
|
||||
map[string]interface{}{
|
||||
"foo": "bar",
|
||||
},
|
||||
[]interface{}{
|
||||
[]interface{}{
|
||||
map[string]interface{}{
|
||||
"foo": "baz",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: map[string]interface{}{
|
||||
"foo": "baz",
|
||||
},
|
||||
expectResult: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, testCase := range testCases {
|
||||
t.Run(testCase.name, func(t *testing.T) {
|
||||
result := findMustNotExist(t, testCase.actual, testCase.expected)
|
||||
if result != testCase.expectResult {
|
||||
t.Errorf("expected %v, got %v", testCase.expectResult, result)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -26,4 +26,5 @@ var (
|
||||
IsWasmPluginTest = flag.Bool("isWasmPluginTest", false, "Determine if run wasm plugin conformance test")
|
||||
WasmPluginType = flag.String("wasmPluginType", "GO", "Define wasm plugin type, currently supports GO, CPP")
|
||||
WasmPluginName = flag.String("wasmPluginName", "", "Define wasm plugin name")
|
||||
IsEnvoyConfigTest = flag.Bool("isEnvoyConfigTest", false, "Determine if run envoy config conformance test")
|
||||
)
|
||||
|
||||
@@ -121,7 +121,7 @@ func FindPodConditionInList(t *testing.T, conditions []v1.PodCondition, condName
|
||||
return false
|
||||
}
|
||||
|
||||
func ApplyConfigmapDataWithYaml(c client.Client, namespace string, name string, key string, val any) error {
|
||||
func ApplyConfigmapDataWithYaml(t *testing.T, c client.Client, namespace string, name string, key string, val any) error {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||
defer cancel()
|
||||
|
||||
@@ -140,8 +140,11 @@ func ApplyConfigmapDataWithYaml(c client.Client, namespace string, name string,
|
||||
}
|
||||
cm.Data[key] = data
|
||||
|
||||
t.Logf("🏗 Updating %s %s", name, namespace)
|
||||
|
||||
if err := c.Update(ctx, cm); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -31,6 +31,9 @@ const (
|
||||
EurekaConformanceFeature SupportedFeature = "eureka"
|
||||
ConsulConformanceFeature SupportedFeature = "consul"
|
||||
NacosConformanceFeature SupportedFeature = "nacos"
|
||||
|
||||
// extended: envoy config
|
||||
EnvoyConfigConformanceFeature SupportedFeature = "envoy-config"
|
||||
)
|
||||
|
||||
var AllFeatures = sets.Set{}.
|
||||
@@ -38,7 +41,8 @@ var AllFeatures = sets.Set{}.
|
||||
Insert(string(DubboConformanceFeature)).
|
||||
Insert(string(EurekaConformanceFeature)).
|
||||
Insert(string(ConsulConformanceFeature)).
|
||||
Insert(string(NacosConformanceFeature))
|
||||
Insert(string(NacosConformanceFeature)).
|
||||
Insert(string(EnvoyConfigConformanceFeature))
|
||||
|
||||
var ExperimentFeatures = sets.Set{}.
|
||||
Insert(string(WASMGoConformanceFeature)).
|
||||
|
||||
@@ -60,6 +60,9 @@ type Options struct {
|
||||
// resources such as Gateways should be cleaned up after the run.
|
||||
CleanupBaseResources bool
|
||||
TimeoutConfig config.TimeoutConfig
|
||||
|
||||
// IsEnvoyConfigTest indicates whether or not the test is for envoy config
|
||||
IsEnvoyConfigTest bool
|
||||
}
|
||||
|
||||
type WASMOptions struct {
|
||||
@@ -87,6 +90,8 @@ func New(s Options) *ConformanceTestSuite {
|
||||
} else {
|
||||
s.SupportedFeatures.Insert(string(WASMGoConformanceFeature))
|
||||
}
|
||||
} else if s.IsEnvoyConfigTest {
|
||||
s.SupportedFeatures.Insert(string(EnvoyConfigConformanceFeature))
|
||||
} else if s.EnableAllSupportedFeatures {
|
||||
s.SupportedFeatures = AllFeatures
|
||||
}
|
||||
|
||||
@@ -51,6 +51,7 @@ func TestHigressConformanceTests(t *testing.T) {
|
||||
},
|
||||
GatewayAddress: "localhost",
|
||||
EnableAllSupportedFeatures: true,
|
||||
IsEnvoyConfigTest: *flags.IsEnvoyConfigTest,
|
||||
})
|
||||
|
||||
cSuite.Setup(t)
|
||||
|
||||
Reference in New Issue
Block a user