blob: 89bd16233bd519df8094e8f3a1d00bc6d2279061 [file] [log] [blame]
// Copyright Istio 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 retry_test
import (
"reflect"
"testing"
"time"
)
import (
envoyroute "github.com/envoyproxy/go-control-plane/envoy/config/route/v3"
previouspriorities "github.com/envoyproxy/go-control-plane/envoy/extensions/retry/priority/previous_priorities/v3"
. "github.com/onsi/gomega"
"google.golang.org/protobuf/types/known/durationpb"
wrappers "google.golang.org/protobuf/types/known/wrapperspb"
networking "istio.io/api/networking/v1alpha3"
)
import (
"github.com/apache/dubbo-go-pixiu/pilot/pkg/networking/core/v1alpha3/route/retry"
"github.com/apache/dubbo-go-pixiu/pilot/pkg/networking/util"
)
func TestRetry(t *testing.T) {
testCases := []struct {
name string
route *networking.HTTPRoute
assertFunc func(g *WithT, policy *envoyroute.RetryPolicy)
}{
{
name: "TestNilRetryShouldReturnDefault",
// Create a route where no retry policy has been explicitly set.
route: &networking.HTTPRoute{},
assertFunc: func(g *WithT, policy *envoyroute.RetryPolicy) {
g.Expect(policy).To(Not(BeNil()))
g.Expect(policy).To(Equal(retry.DefaultPolicy()))
},
},
{
name: "TestZeroAttemptsShouldReturnNilPolicy",
// Create a route with a retry policy with zero attempts configured.
route: &networking.HTTPRoute{
Retries: &networking.HTTPRetry{
// Explicitly not retrying.
Attempts: 0,
},
},
assertFunc: func(g *WithT, policy *envoyroute.RetryPolicy) {
g.Expect(policy).To(BeNil())
},
},
{
name: "TestRetryWithAllFieldsSet",
// Create a route with a retry policy with all fields configured.
route: &networking.HTTPRoute{
Retries: &networking.HTTPRetry{
Attempts: 2,
RetryOn: "some,fake,conditions",
PerTryTimeout: durationpb.New(time.Second * 3),
},
},
assertFunc: func(g *WithT, policy *envoyroute.RetryPolicy) {
g.Expect(policy).To(Not(BeNil()))
g.Expect(policy.RetryOn).To(Equal("some,fake,conditions"))
g.Expect(policy.PerTryTimeout).To(Equal(durationpb.New(time.Second * 3)))
g.Expect(policy.NumRetries.Value).To(Equal(uint32(2)))
g.Expect(policy.RetriableStatusCodes).To(Equal(make([]uint32, 0)))
g.Expect(policy.RetryPriority).To(BeNil())
g.Expect(policy.HostSelectionRetryMaxAttempts).To(Equal(retry.DefaultPolicy().HostSelectionRetryMaxAttempts))
g.Expect(policy.RetryHostPredicate).To(Equal(retry.DefaultPolicy().RetryHostPredicate))
},
},
{
name: "TestRetryOnWithEmptyParts",
// Create a route with a retry policy with empty retry conditions configured.
route: &networking.HTTPRoute{
Retries: &networking.HTTPRetry{
// Explicitly not retrying.
Attempts: 2,
RetryOn: "some,fake,conditions,,,",
},
},
assertFunc: func(g *WithT, policy *envoyroute.RetryPolicy) {
g.Expect(policy).To(Not(BeNil()))
g.Expect(policy.RetryOn).To(Equal("some,fake,conditions"))
g.Expect(policy.RetriableStatusCodes).To(Equal([]uint32{}))
},
},
{
name: "TestRetryOnWithRetriableStatusCodes",
// Create a route with a retry policy with retriable status code.
route: &networking.HTTPRoute{
Retries: &networking.HTTPRetry{
// Explicitly not retrying.
Attempts: 2,
RetryOn: "gateway-error,retriable-status-codes,503",
},
},
assertFunc: func(g *WithT, policy *envoyroute.RetryPolicy) {
g.Expect(policy).To(Not(BeNil()))
g.Expect(policy.RetryOn).To(Equal("gateway-error,retriable-status-codes"))
g.Expect(policy.RetriableStatusCodes).To(Equal([]uint32{503}))
},
},
{
name: "TestRetryOnWithWhitespace",
// Create a route with a retry policy with retryOn having white spaces.
route: &networking.HTTPRoute{
Retries: &networking.HTTPRetry{
// Explicitly not retrying.
Attempts: 2,
RetryOn: " some, ,fake , conditions, ,",
},
},
assertFunc: func(g *WithT, policy *envoyroute.RetryPolicy) {
g.Expect(policy).To(Not(BeNil()))
g.Expect(policy.RetryOn).To(Equal("some,fake,conditions"))
g.Expect(policy.RetriableStatusCodes).To(Equal([]uint32{}))
},
},
{
name: "TestRetryOnContainingStatusCodes",
// Create a route with a retry policy with status codes.
route: &networking.HTTPRoute{
Retries: &networking.HTTPRetry{
Attempts: 2,
RetryOn: "some,fake,5xx,404,conditions,503",
},
},
assertFunc: func(g *WithT, policy *envoyroute.RetryPolicy) {
g.Expect(policy).To(Not(BeNil()))
g.Expect(policy.RetryOn).To(Equal("some,fake,5xx,conditions,retriable-status-codes"))
g.Expect(policy.RetriableStatusCodes).To(Equal([]uint32{404, 503}))
},
},
{
name: "TestRetryOnWithInvalidStatusCodesShouldAddToRetryOn",
// Create a route with a retry policy with invalid status codes.
route: &networking.HTTPRoute{
Retries: &networking.HTTPRetry{
Attempts: 2,
RetryOn: "some,fake,conditions,1000",
},
},
assertFunc: func(g *WithT, policy *envoyroute.RetryPolicy) {
g.Expect(policy).To(Not(BeNil()))
g.Expect(policy.RetryOn).To(Equal("some,fake,conditions,1000"))
g.Expect(policy.RetriableStatusCodes).To(Equal([]uint32{}))
},
},
{
name: "TestMissingRetryOnShouldReturnDefaults",
// Create a route with a retry policy with two attempts configured.
route: &networking.HTTPRoute{
Retries: &networking.HTTPRetry{
Attempts: 2,
},
},
assertFunc: func(g *WithT, policy *envoyroute.RetryPolicy) {
g.Expect(policy).To(Not(BeNil()))
g.Expect(policy.RetryOn).To(Equal(retry.DefaultPolicy().RetryOn))
g.Expect(policy.RetriableStatusCodes).To(Equal(retry.DefaultPolicy().RetriableStatusCodes))
},
},
{
name: "TestMissingPerTryTimeoutShouldReturnNil",
// Create a route with a retry policy without per try timeout.
route: &networking.HTTPRoute{
Retries: &networking.HTTPRetry{
Attempts: 2,
},
},
assertFunc: func(g *WithT, policy *envoyroute.RetryPolicy) {
g.Expect(policy).To(Not(BeNil()))
g.Expect(policy.PerTryTimeout).To(BeNil())
},
},
{
name: "TestRetryRemoteLocalities",
// Create a route with a retry policy with RetryRemoteLocalities enabled.
route: &networking.HTTPRoute{
Retries: &networking.HTTPRetry{
Attempts: 2,
RetryRemoteLocalities: &wrappers.BoolValue{
Value: true,
},
},
},
assertFunc: func(g *WithT, policy *envoyroute.RetryPolicy) {
g.Expect(policy).To(Not(BeNil()))
g.Expect(policy.RetryOn).To(Equal(retry.DefaultPolicy().RetryOn))
g.Expect(policy.RetriableStatusCodes).To(Equal(retry.DefaultPolicy().RetriableStatusCodes))
previousPrioritiesConfig := &previouspriorities.PreviousPrioritiesConfig{
UpdateFrequency: int32(2),
}
expected := &envoyroute.RetryPolicy_RetryPriority{
Name: "envoy.retry_priorities.previous_priorities",
ConfigType: &envoyroute.RetryPolicy_RetryPriority_TypedConfig{
TypedConfig: util.MessageToAny(previousPrioritiesConfig),
},
}
if !reflect.DeepEqual(policy.RetryPriority, expected) {
t.Fatalf("Expected %v, actual %v", expected, policy.RetryPriority)
}
},
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
g := NewWithT(t)
policy := retry.ConvertPolicy(tc.route.Retries)
if tc.assertFunc != nil {
tc.assertFunc(g, policy)
}
})
}
}