From d6e2567f78ae63f1798978010dde362e1c5db1bf Mon Sep 17 00:00:00 2001 From: Nick Irvine <115657443+nfi-hashicorp@users.noreply.github.com> Date: Fri, 17 Mar 2023 13:16:06 -0700 Subject: [PATCH] add upgrade tests for GRPC, ingress gateway GRPC (attempt #2) [NET-2296] (#4741) --- .../consul-container/libs/assert/grpc.go | 36 +++++ .../test/upgrade/ingress_gateway_grpc_test.go | 124 ++++++++++++++++++ 2 files changed, 160 insertions(+) create mode 100644 test/integration/consul-container/libs/assert/grpc.go create mode 100644 test/integration/consul-container/test/upgrade/ingress_gateway_grpc_test.go diff --git a/test/integration/consul-container/libs/assert/grpc.go b/test/integration/consul-container/libs/assert/grpc.go new file mode 100644 index 000000000000..318fce797282 --- /dev/null +++ b/test/integration/consul-container/libs/assert/grpc.go @@ -0,0 +1,36 @@ +package assert + +import ( + "context" + "testing" + "time" + + "fortio.org/fortio/fgrpc" + "github.com/hashicorp/consul/sdk/testutil/retry" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "google.golang.org/grpc" + "google.golang.org/grpc/credentials/insecure" +) + +// GRPCPing sends a fgrpc.PingMessage to a fortio server at addr, analogous to +// the CLI command `fortio grpcping`. It retries for up to 1m, with a 25ms gap. +func GRPCPing(t *testing.T, addr string) { + t.Helper() + pingConn, err := grpc.Dial(addr, grpc.WithTransportCredentials(insecure.NewCredentials())) + require.NoError(t, err) + pingCl := fgrpc.NewPingServerClient(pingConn) + var msg *fgrpc.PingMessage + retries := 0 + retry.RunWith(&retry.Timer{Timeout: time.Minute, Wait: 25 * time.Millisecond}, t, func(r *retry.R) { + retries += 1 + msg, err = pingCl.Ping(context.Background(), &fgrpc.PingMessage{ + // use addr as payload so we have something variable to check against + Payload: addr, + }) + if err != nil { + r.Error(err) + } + }) + assert.Equal(t, addr, msg.Payload) +} diff --git a/test/integration/consul-container/test/upgrade/ingress_gateway_grpc_test.go b/test/integration/consul-container/test/upgrade/ingress_gateway_grpc_test.go new file mode 100644 index 000000000000..21c6738c9c0f --- /dev/null +++ b/test/integration/consul-container/test/upgrade/ingress_gateway_grpc_test.go @@ -0,0 +1,124 @@ +package upgrade + +import ( + "context" + "fmt" + "testing" + + "github.com/docker/go-connections/nat" + "github.com/stretchr/testify/require" + + "github.com/hashicorp/consul/api" + libassert "github.com/hashicorp/consul/test/integration/consul-container/libs/assert" + libcluster "github.com/hashicorp/consul/test/integration/consul-container/libs/cluster" + libservice "github.com/hashicorp/consul/test/integration/consul-container/libs/service" + "github.com/hashicorp/consul/test/integration/consul-container/libs/topology" + "github.com/hashicorp/consul/test/integration/consul-container/libs/utils" +) + +func TestIngressGateway_GRPC_UpgradeToTarget_fromLatest(t *testing.T) { + t.Parallel() + cluster, _, client := topology.NewCluster(t, &topology.ClusterConfig{ + NumServers: 1, + NumClients: 1, + BuildOpts: &libcluster.BuildOptions{ + Datacenter: "dc1", + ConsulVersion: utils.LatestVersion, + }, + ApplyDefaultProxySettings: true, + }) + + require.NoError(t, cluster.ConfigEntryWrite(&api.ServiceConfigEntry{ + Name: libservice.StaticServerServiceName, + Kind: api.ServiceDefaults, + Protocol: "grpc", + })) + + const ( + nameIG = "ingress-gateway" + ) + + const nameS1 = libservice.StaticServerServiceName + + igw, err := libservice.NewGatewayService( + context.Background(), + libservice.GatewayConfig{ + Name: nameIG, + Kind: "ingress", + }, + cluster.Servers()[0], + ) + require.NoError(t, err) + + // these must be one of the externally-mapped ports from + // https://github.com/hashicorp/consul/blob/c5e729e86576771c4c22c6da1e57aaa377319323/test/integration/consul-container/libs/cluster/container.go#L521-L525 + const portS1DirectNoTLS = 8080 + require.NoError(t, cluster.ConfigEntryWrite(&api.IngressGatewayConfigEntry{ + Kind: api.IngressGateway, + Name: nameIG, + Listeners: []api.IngressListener{ + { + Port: portS1DirectNoTLS, + Protocol: "grpc", + Services: []api.IngressService{ + { + Name: libservice.StaticServerServiceName, + Hosts: []string{"*"}, + }, + }, + }, + }, + })) + + // register static-server service + _, _, err = libservice.CreateAndRegisterStaticServerAndSidecar( + cluster.Clients()[0], + &libservice.ServiceOpts{ + Name: nameS1, + ID: nameS1, + HTTPPort: 8080, + GRPCPort: 8079, + RegisterGRPC: true, + }, + ) + require.NoError(t, err) + libassert.CatalogServiceExists(t, client, nameS1, nil) + + // Register an static-client service + serverNodes := cluster.Servers() + require.NoError(t, err) + require.True(t, len(serverNodes) > 0) + staticClientSvcSidecar, err := libservice.CreateAndRegisterStaticClientSidecar(serverNodes[0], "", true) + require.NoError(t, err) + + tests := func(t *testing.T) { + t.Run("grpc directly", func(t *testing.T) { + _, p := staticClientSvcSidecar.GetAddr() + libassert.GRPCPing(t, fmt.Sprintf("localhost:%d", p)) + }) + t.Run("grpc via igw", func(t *testing.T) { + pm, _ := cluster.Servers()[0].GetPod().MappedPort( + context.Background(), + nat.Port(fmt.Sprintf("%d/tcp", portS1DirectNoTLS)), + ) + libassert.GRPCPing(t, fmt.Sprintf("localhost:%d", pm.Int())) + }) + } + + t.Run("pre-upgrade", func(t *testing.T) { + tests(t) + }) + + if t.Failed() { + t.Fatal("failing fast: failed assertions pre-upgrade") + } + + t.Logf("Upgrade to version %s", utils.TargetVersion) + err = cluster.StandardUpgrade(t, context.Background(), utils.TargetVersion) + require.NoError(t, err) + require.NoError(t, igw.Restart()) + + t.Run("post-upgrade", func(t *testing.T) { + tests(t) + }) +}