2020-09-11 18:15:02 +00:00
|
|
|
package grpc
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"fmt"
|
2020-09-15 18:11:48 +00:00
|
|
|
"net"
|
2020-09-11 18:15:02 +00:00
|
|
|
"strings"
|
|
|
|
"testing"
|
|
|
|
"time"
|
|
|
|
|
|
|
|
"github.com/hashicorp/consul/agent/grpc/internal/testservice"
|
|
|
|
"github.com/hashicorp/consul/agent/grpc/resolver"
|
|
|
|
"github.com/hashicorp/consul/agent/metadata"
|
2020-09-14 20:16:44 +00:00
|
|
|
"github.com/hashicorp/consul/sdk/testutil/retry"
|
2020-09-11 18:15:02 +00:00
|
|
|
"github.com/stretchr/testify/require"
|
|
|
|
)
|
|
|
|
|
2020-09-15 18:11:48 +00:00
|
|
|
func TestNewDialer_WithTLSWrapper(t *testing.T) {
|
|
|
|
lis, err := net.Listen("tcp", "127.0.0.1:0")
|
|
|
|
require.NoError(t, err)
|
|
|
|
t.Cleanup(logError(t, lis.Close))
|
|
|
|
|
|
|
|
builder := resolver.NewServerResolverBuilder(resolver.Config{})
|
|
|
|
builder.AddServer(&metadata.Server{
|
|
|
|
Name: "server-1",
|
|
|
|
ID: "ID1",
|
|
|
|
Datacenter: "dc1",
|
|
|
|
Addr: lis.Addr(),
|
|
|
|
UseTLS: true,
|
|
|
|
})
|
|
|
|
|
|
|
|
var called bool
|
|
|
|
wrapper := func(_ string, conn net.Conn) (net.Conn, error) {
|
|
|
|
called = true
|
|
|
|
return conn, nil
|
|
|
|
}
|
|
|
|
dial := newDialer(builder, wrapper)
|
|
|
|
ctx := context.Background()
|
|
|
|
conn, err := dial(ctx, lis.Addr().String())
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.NoError(t, conn.Close())
|
|
|
|
require.True(t, called, "expected TLSWrapper to be called")
|
2020-09-11 18:15:02 +00:00
|
|
|
}
|
|
|
|
|
2020-09-15 18:11:48 +00:00
|
|
|
// TODO: integration test TestNewDialer with TLS and rcp server, when the rpc
|
|
|
|
// exists as an isolated component.
|
|
|
|
|
2020-09-11 18:15:02 +00:00
|
|
|
func TestClientConnPool_IntegrationWithGRPCResolver_Failover(t *testing.T) {
|
|
|
|
count := 4
|
2020-09-14 20:16:44 +00:00
|
|
|
cfg := resolver.Config{Scheme: newScheme(t.Name())}
|
|
|
|
res := resolver.NewServerResolverBuilder(cfg)
|
2020-09-11 18:15:02 +00:00
|
|
|
resolver.RegisterWithGRPC(res)
|
|
|
|
pool := NewClientConnPool(res, nil)
|
|
|
|
|
|
|
|
for i := 0; i < count; i++ {
|
|
|
|
name := fmt.Sprintf("server-%d", i)
|
|
|
|
srv := newTestServer(t, name, "dc1")
|
|
|
|
res.AddServer(srv.Metadata())
|
|
|
|
t.Cleanup(srv.shutdown)
|
|
|
|
}
|
|
|
|
|
|
|
|
conn, err := pool.ClientConn("dc1")
|
|
|
|
require.NoError(t, err)
|
|
|
|
client := testservice.NewSimpleClient(conn)
|
|
|
|
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
|
|
|
|
t.Cleanup(cancel)
|
|
|
|
|
|
|
|
first, err := client.Something(ctx, &testservice.Req{})
|
|
|
|
require.NoError(t, err)
|
2020-09-14 20:16:44 +00:00
|
|
|
|
2020-09-11 18:15:02 +00:00
|
|
|
res.RemoveServer(&metadata.Server{ID: first.ServerName, Datacenter: "dc1"})
|
|
|
|
|
|
|
|
resp, err := client.Something(ctx, &testservice.Req{})
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.NotEqual(t, resp.ServerName, first.ServerName)
|
|
|
|
}
|
|
|
|
|
|
|
|
func newScheme(n string) string {
|
|
|
|
s := strings.Replace(n, "/", "", -1)
|
|
|
|
s = strings.Replace(s, "_", "", -1)
|
|
|
|
return strings.ToLower(s)
|
|
|
|
}
|
|
|
|
|
2020-09-14 20:16:44 +00:00
|
|
|
func TestClientConnPool_IntegrationWithGRPCResolver_Rebalance(t *testing.T) {
|
|
|
|
count := 4
|
|
|
|
cfg := resolver.Config{Scheme: newScheme(t.Name())}
|
|
|
|
res := resolver.NewServerResolverBuilder(cfg)
|
|
|
|
resolver.RegisterWithGRPC(res)
|
|
|
|
pool := NewClientConnPool(res, nil)
|
2020-09-11 18:15:02 +00:00
|
|
|
|
2020-09-14 20:16:44 +00:00
|
|
|
for i := 0; i < count; i++ {
|
|
|
|
name := fmt.Sprintf("server-%d", i)
|
|
|
|
srv := newTestServer(t, name, "dc1")
|
|
|
|
res.AddServer(srv.Metadata())
|
|
|
|
t.Cleanup(srv.shutdown)
|
|
|
|
}
|
|
|
|
|
|
|
|
conn, err := pool.ClientConn("dc1")
|
|
|
|
require.NoError(t, err)
|
|
|
|
client := testservice.NewSimpleClient(conn)
|
|
|
|
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
|
|
|
|
t.Cleanup(cancel)
|
|
|
|
|
|
|
|
first, err := client.Something(ctx, &testservice.Req{})
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
t.Run("rebalance a different DC, does nothing", func(t *testing.T) {
|
|
|
|
res.NewRebalancer("dc-other")()
|
|
|
|
|
|
|
|
resp, err := client.Something(ctx, &testservice.Req{})
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, resp.ServerName, first.ServerName)
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("rebalance the dc", func(t *testing.T) {
|
|
|
|
// Rebalance is random, but if we repeat it a few times it should give us a
|
|
|
|
// new server.
|
|
|
|
retry.RunWith(fastRetry, t, func(r *retry.R) {
|
|
|
|
res.NewRebalancer("dc1")()
|
|
|
|
|
|
|
|
resp, err := client.Something(ctx, &testservice.Req{})
|
|
|
|
require.NoError(r, err)
|
|
|
|
require.NotEqual(r, resp.ServerName, first.ServerName)
|
|
|
|
})
|
|
|
|
})
|
2020-09-11 18:15:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func TestClientConnPool_IntegrationWithGRPCResolver_MultiDC(t *testing.T) {
|
|
|
|
dcs := []string{"dc1", "dc2", "dc3"}
|
|
|
|
|
2020-09-14 20:16:44 +00:00
|
|
|
cfg := resolver.Config{Scheme: newScheme(t.Name())}
|
|
|
|
res := resolver.NewServerResolverBuilder(cfg)
|
2020-09-11 18:15:02 +00:00
|
|
|
resolver.RegisterWithGRPC(res)
|
|
|
|
pool := NewClientConnPool(res, nil)
|
|
|
|
|
|
|
|
for _, dc := range dcs {
|
|
|
|
name := "server-0-" + dc
|
|
|
|
srv := newTestServer(t, name, dc)
|
|
|
|
res.AddServer(srv.Metadata())
|
|
|
|
t.Cleanup(srv.shutdown)
|
|
|
|
}
|
|
|
|
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
|
|
|
|
t.Cleanup(cancel)
|
|
|
|
|
|
|
|
for _, dc := range dcs {
|
|
|
|
conn, err := pool.ClientConn(dc)
|
|
|
|
require.NoError(t, err)
|
|
|
|
client := testservice.NewSimpleClient(conn)
|
|
|
|
|
|
|
|
resp, err := client.Something(ctx, &testservice.Req{})
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, resp.Datacenter, dc)
|
|
|
|
}
|
|
|
|
}
|