mirror of https://github.com/status-im/consul.git
Retry and timeout test acceptance test (#18791)
* retry and timeout test * add docker mirrior * checkpoint * add in error * add in delay * up error rate * fix status code
This commit is contained in:
parent
6838441c54
commit
753c8f1774
|
@ -9,5 +9,5 @@ import (
|
||||||
|
|
||||||
const (
|
const (
|
||||||
envoyLogLevel = "debug"
|
envoyLogLevel = "debug"
|
||||||
hashicorpDockerProxy = "docker.mirror.hashicorp.services"
|
HashicorpDockerProxy = "docker.mirror.hashicorp.services"
|
||||||
)
|
)
|
||||||
|
|
|
@ -187,7 +187,7 @@ func NewExampleService(ctx context.Context, name string, httpPort int, grpcPort
|
||||||
command = append(command, containerArgs...)
|
command = append(command, containerArgs...)
|
||||||
|
|
||||||
req := testcontainers.ContainerRequest{
|
req := testcontainers.ContainerRequest{
|
||||||
Image: hashicorpDockerProxy + "/fortio/fortio",
|
Image: HashicorpDockerProxy + "/fortio/fortio",
|
||||||
WaitingFor: wait.ForLog("").WithStartupTimeout(60 * time.Second),
|
WaitingFor: wait.ForLog("").WithStartupTimeout(60 * time.Second),
|
||||||
AutoRemove: false,
|
AutoRemove: false,
|
||||||
Name: containerName,
|
Name: containerName,
|
||||||
|
|
|
@ -227,6 +227,7 @@ type checkOptions struct {
|
||||||
responseHeaders map[string]string
|
responseHeaders map[string]string
|
||||||
statusCode int
|
statusCode int
|
||||||
testName string
|
testName string
|
||||||
|
expectedBody string
|
||||||
}
|
}
|
||||||
|
|
||||||
// checkRoute, customized version of libassert.RouteEchos to allow for headers/distinguishing between the server instances
|
// checkRoute, customized version of libassert.RouteEchos to allow for headers/distinguishing between the server instances
|
||||||
|
@ -289,8 +290,13 @@ func checkRoute(t *testing.T, port int, path string, headers map[string]string,
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !strings.Contains(string(body), "hello") {
|
expectedBody := expected.expectedBody
|
||||||
t.Log("body does not contain 'hello'")
|
if expectedBody == "" {
|
||||||
|
expectedBody = "hello"
|
||||||
|
}
|
||||||
|
if !strings.Contains(string(body), expectedBody) {
|
||||||
|
t.Log(string(body))
|
||||||
|
t.Log("body does not contain " + expectedBody)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,8 @@ import (
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/testcontainers/testcontainers-go"
|
||||||
|
"k8s.io/utils/pointer"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
@ -737,3 +739,233 @@ func TestHTTPRouteParentRefChange(t *testing.T) {
|
||||||
"Host": "test.foo",
|
"Host": "test.foo",
|
||||||
}, "")
|
}, "")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestHTTPRouteRetryAndTimeout(t *testing.T) {
|
||||||
|
if testing.Short() {
|
||||||
|
t.Skip("too slow for testing.Short")
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
// infrastructure set up
|
||||||
|
listenerPort := 6018
|
||||||
|
retryServiceHTTPPort := 6019
|
||||||
|
retryServiceGRPCPort := 6020
|
||||||
|
timeoutServiceHTTPPort := 6021
|
||||||
|
timeoutServiceGRPCPort := 6022
|
||||||
|
|
||||||
|
retryServiceName := randomName("service", 16)
|
||||||
|
gatewayName := randomName("gw", 16)
|
||||||
|
retryRouteName := randomName("route", 16)
|
||||||
|
timeoutServiceName := randomName("service", 16)
|
||||||
|
timeoutRouteName := randomName("route", 16)
|
||||||
|
retryPath := "/retry"
|
||||||
|
timeoutPath := "/timeout"
|
||||||
|
|
||||||
|
clusterConfig := &libtopology.ClusterConfig{
|
||||||
|
NumServers: 1,
|
||||||
|
NumClients: 1,
|
||||||
|
BuildOpts: &libcluster.BuildOptions{
|
||||||
|
Datacenter: "dc1",
|
||||||
|
InjectAutoEncryption: true,
|
||||||
|
InjectGossipEncryption: true,
|
||||||
|
AllowHTTPAnyway: true,
|
||||||
|
},
|
||||||
|
ExposedPorts: []int{
|
||||||
|
listenerPort,
|
||||||
|
retryServiceGRPCPort,
|
||||||
|
retryServiceHTTPPort,
|
||||||
|
timeoutServiceGRPCPort,
|
||||||
|
timeoutServiceHTTPPort,
|
||||||
|
},
|
||||||
|
ApplyDefaultProxySettings: true,
|
||||||
|
}
|
||||||
|
|
||||||
|
cluster, _, _ := libtopology.NewCluster(t, clusterConfig)
|
||||||
|
client := cluster.Agents[0].GetClient()
|
||||||
|
|
||||||
|
namespace := getOrCreateNamespace(t, client)
|
||||||
|
|
||||||
|
_, _, err := libservice.CreateAndRegisterCustomServiceAndSidecar(
|
||||||
|
cluster.Agents[0], &libservice.ServiceOpts{
|
||||||
|
ID: retryServiceName,
|
||||||
|
Name: retryServiceName,
|
||||||
|
Namespace: namespace,
|
||||||
|
HTTPPort: retryServiceHTTPPort,
|
||||||
|
GRPCPort: retryServiceGRPCPort,
|
||||||
|
},
|
||||||
|
testcontainers.ContainerRequest{
|
||||||
|
Image: libservice.HashicorpDockerProxy + "/nicholasjackson/fake-service:v0.26.0",
|
||||||
|
Env: map[string]string{
|
||||||
|
"LISTEN_ADDR": fmt.Sprintf("0.0.0.0:%d", retryServiceHTTPPort),
|
||||||
|
"ERROR_RATE": "0.5",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
nil,
|
||||||
|
)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
_, _, err = libservice.CreateAndRegisterCustomServiceAndSidecar(
|
||||||
|
cluster.Agents[0], &libservice.ServiceOpts{
|
||||||
|
ID: timeoutServiceName,
|
||||||
|
Name: timeoutServiceName,
|
||||||
|
Namespace: namespace,
|
||||||
|
HTTPPort: timeoutServiceHTTPPort,
|
||||||
|
GRPCPort: timeoutServiceGRPCPort,
|
||||||
|
},
|
||||||
|
testcontainers.ContainerRequest{
|
||||||
|
Image: libservice.HashicorpDockerProxy + "/nicholasjackson/fake-service:v0.26.0",
|
||||||
|
Env: map[string]string{
|
||||||
|
"LISTEN_ADDR": fmt.Sprintf("0.0.0.0:%d", timeoutServiceHTTPPort),
|
||||||
|
"ERROR_RATE": "1.0",
|
||||||
|
"ERROR_DELAY": "1m",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
nil,
|
||||||
|
)
|
||||||
|
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
// write config entries
|
||||||
|
proxyDefaults := &api.ProxyConfigEntry{
|
||||||
|
Kind: api.ProxyDefaults,
|
||||||
|
Name: api.ProxyConfigGlobal,
|
||||||
|
Config: map[string]interface{}{
|
||||||
|
"protocol": "http",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
require.NoError(t, cluster.ConfigEntryWrite(proxyDefaults))
|
||||||
|
|
||||||
|
apiGateway := &api.APIGatewayConfigEntry{
|
||||||
|
Kind: "api-gateway",
|
||||||
|
Name: gatewayName,
|
||||||
|
Listeners: []api.APIGatewayListener{
|
||||||
|
{
|
||||||
|
Name: "listener",
|
||||||
|
Port: listenerPort,
|
||||||
|
Protocol: "http",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Namespace: namespace,
|
||||||
|
}
|
||||||
|
|
||||||
|
retryRoute := &api.HTTPRouteConfigEntry{
|
||||||
|
Kind: api.HTTPRoute,
|
||||||
|
Name: retryRouteName,
|
||||||
|
Namespace: namespace,
|
||||||
|
Parents: []api.ResourceReference{
|
||||||
|
{
|
||||||
|
Kind: api.APIGateway,
|
||||||
|
Name: gatewayName,
|
||||||
|
Namespace: namespace,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Hostnames: []string{
|
||||||
|
"test.foo",
|
||||||
|
"test.example",
|
||||||
|
},
|
||||||
|
Rules: []api.HTTPRouteRule{
|
||||||
|
{
|
||||||
|
Filters: api.HTTPFilters{
|
||||||
|
RetryFilter: &api.RetryFilter{
|
||||||
|
NumRetries: pointer.Uint32(10),
|
||||||
|
RetryOnStatusCodes: []uint32{500},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Services: []api.HTTPService{
|
||||||
|
{
|
||||||
|
Name: retryServiceName,
|
||||||
|
Namespace: namespace,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Matches: []api.HTTPMatch{
|
||||||
|
{
|
||||||
|
Path: api.HTTPPathMatch{
|
||||||
|
Match: api.HTTPPathMatchPrefix,
|
||||||
|
Value: retryPath,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
timeoutRoute := &api.HTTPRouteConfigEntry{
|
||||||
|
Kind: api.HTTPRoute,
|
||||||
|
Name: timeoutRouteName,
|
||||||
|
Namespace: namespace,
|
||||||
|
Parents: []api.ResourceReference{
|
||||||
|
{
|
||||||
|
Kind: api.APIGateway,
|
||||||
|
Name: gatewayName,
|
||||||
|
Namespace: namespace,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Hostnames: []string{
|
||||||
|
"test.foo",
|
||||||
|
"test.example",
|
||||||
|
},
|
||||||
|
Rules: []api.HTTPRouteRule{
|
||||||
|
{
|
||||||
|
Filters: api.HTTPFilters{
|
||||||
|
TimeoutFilter: &api.TimeoutFilter{
|
||||||
|
RequestTimeout: 1,
|
||||||
|
IdleTimeout: 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Services: []api.HTTPService{
|
||||||
|
{
|
||||||
|
Name: timeoutServiceName,
|
||||||
|
Namespace: namespace,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Matches: []api.HTTPMatch{
|
||||||
|
{
|
||||||
|
Path: api.HTTPPathMatch{
|
||||||
|
Match: api.HTTPPathMatchPrefix,
|
||||||
|
Value: timeoutPath,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
require.NoError(t, cluster.ConfigEntryWrite(apiGateway))
|
||||||
|
require.NoError(t, cluster.ConfigEntryWrite(timeoutRoute))
|
||||||
|
require.NoError(t, cluster.ConfigEntryWrite(retryRoute))
|
||||||
|
|
||||||
|
// create gateway service
|
||||||
|
gwCfg := libservice.GatewayConfig{
|
||||||
|
Name: gatewayName,
|
||||||
|
Kind: "api",
|
||||||
|
Namespace: namespace,
|
||||||
|
}
|
||||||
|
gatewayService, err := libservice.NewGatewayService(context.Background(), gwCfg, cluster.Agents[0], listenerPort)
|
||||||
|
require.NoError(t, err)
|
||||||
|
libassert.CatalogServiceExists(t, client, gatewayName, &api.QueryOptions{Namespace: namespace})
|
||||||
|
|
||||||
|
// make sure config entries have been properly created
|
||||||
|
checkGatewayConfigEntry(t, client, gatewayName, &api.QueryOptions{Namespace: namespace})
|
||||||
|
t.Log("checking retry route")
|
||||||
|
checkHTTPRouteConfigEntry(t, client, retryRouteName, &api.QueryOptions{Namespace: namespace})
|
||||||
|
|
||||||
|
t.Log("checking timeout route")
|
||||||
|
checkHTTPRouteConfigEntry(t, client, timeoutRouteName, &api.QueryOptions{Namespace: namespace})
|
||||||
|
|
||||||
|
// gateway resolves routes
|
||||||
|
gatewayPort, err := gatewayService.GetPort(listenerPort)
|
||||||
|
require.NoError(t, err)
|
||||||
|
fmt.Println("Gateway Port: ", gatewayPort)
|
||||||
|
|
||||||
|
// hit service 1 by hitting root path
|
||||||
|
checkRoute(t, gatewayPort, retryPath, map[string]string{
|
||||||
|
"Host": "test.foo",
|
||||||
|
}, checkOptions{debug: false, statusCode: 200, testName: "retry should succeed cleanly", expectedBody: "Hello World"})
|
||||||
|
|
||||||
|
checkRoute(t, gatewayPort, timeoutPath, map[string]string{
|
||||||
|
"Host": "test.foo",
|
||||||
|
}, checkOptions{debug: false, statusCode: 500, testName: "timeout should timeout", expectedBody: "timeout"})
|
||||||
|
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue