mirror of https://github.com/hashicorp/consul
251 lines
6.1 KiB
Go
251 lines
6.1 KiB
Go
// Copyright (c) HashiCorp, Inc.
|
|
// SPDX-License-Identifier: BUSL-1.1
|
|
|
|
package consul
|
|
|
|
import (
|
|
"fmt"
|
|
"regexp"
|
|
"testing"
|
|
|
|
"github.com/hashicorp/go-version"
|
|
"github.com/hashicorp/serf/serf"
|
|
"github.com/stretchr/testify/require"
|
|
|
|
"github.com/hashicorp/consul/agent/metadata"
|
|
)
|
|
|
|
func TestUtil_CanServersUnderstandProtocol(t *testing.T) {
|
|
t.Parallel()
|
|
var members []serf.Member
|
|
|
|
// All empty list cases should return false.
|
|
for v := ProtocolVersionMin; v <= ProtocolVersionMax; v++ {
|
|
grok, err := CanServersUnderstandProtocol(members, v)
|
|
if err != nil {
|
|
t.Fatalf("err: %v", err)
|
|
}
|
|
if grok {
|
|
t.Fatalf("empty list should always return false")
|
|
}
|
|
}
|
|
|
|
// Add a non-server member.
|
|
members = append(members, serf.Member{
|
|
Tags: map[string]string{
|
|
"vsn_min": fmt.Sprintf("%d", ProtocolVersionMin),
|
|
"vsn_max": fmt.Sprintf("%d", ProtocolVersionMax),
|
|
},
|
|
})
|
|
|
|
// Make sure it doesn't get counted.
|
|
for v := ProtocolVersionMin; v <= ProtocolVersionMax; v++ {
|
|
grok, err := CanServersUnderstandProtocol(members, v)
|
|
if err != nil {
|
|
t.Fatalf("err: %v", err)
|
|
}
|
|
if grok {
|
|
t.Fatalf("non-server members should not be counted")
|
|
}
|
|
}
|
|
|
|
// Add a server member.
|
|
members = append(members, serf.Member{
|
|
Tags: map[string]string{
|
|
"role": "consul",
|
|
"vsn_min": fmt.Sprintf("%d", ProtocolVersionMin),
|
|
"vsn_max": fmt.Sprintf("%d", ProtocolVersionMax),
|
|
},
|
|
})
|
|
|
|
// Now it should report that it understands.
|
|
for v := ProtocolVersionMin; v <= ProtocolVersionMax; v++ {
|
|
grok, err := CanServersUnderstandProtocol(members, v)
|
|
if err != nil {
|
|
t.Fatalf("err: %v", err)
|
|
}
|
|
if !grok {
|
|
t.Fatalf("server should grok")
|
|
}
|
|
}
|
|
|
|
// Nobody should understand anything from the future.
|
|
for v := uint8(ProtocolVersionMax + 1); v <= uint8(ProtocolVersionMax+10); v++ {
|
|
grok, err := CanServersUnderstandProtocol(members, v)
|
|
if err != nil {
|
|
t.Fatalf("err: %v", err)
|
|
}
|
|
if grok {
|
|
t.Fatalf("server should not grok")
|
|
}
|
|
}
|
|
|
|
// Add an older server.
|
|
members = append(members, serf.Member{
|
|
Tags: map[string]string{
|
|
"role": "consul",
|
|
"vsn_min": fmt.Sprintf("%d", ProtocolVersionMin),
|
|
"vsn_max": fmt.Sprintf("%d", ProtocolVersionMax-1),
|
|
},
|
|
})
|
|
|
|
// The servers should no longer understand the max version.
|
|
for v := ProtocolVersionMin; v <= ProtocolVersionMax; v++ {
|
|
grok, err := CanServersUnderstandProtocol(members, v)
|
|
if err != nil {
|
|
t.Fatalf("err: %v", err)
|
|
}
|
|
expected := v < ProtocolVersionMax
|
|
if grok != expected {
|
|
t.Fatalf("bad: %v != %v", grok, expected)
|
|
}
|
|
}
|
|
|
|
// Try a version that's too low for the minimum.
|
|
{
|
|
grok, err := CanServersUnderstandProtocol(members, 0)
|
|
if err != nil {
|
|
t.Fatalf("err: %v", err)
|
|
}
|
|
if grok {
|
|
t.Fatalf("server should not grok")
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestIsConsulNode(t *testing.T) {
|
|
t.Parallel()
|
|
m := serf.Member{
|
|
Tags: map[string]string{
|
|
"role": "node",
|
|
"dc": "east-aws",
|
|
},
|
|
}
|
|
valid, dc := isConsulNode(m)
|
|
if !valid || dc != "east-aws" {
|
|
t.Fatalf("bad: %v %v", valid, dc)
|
|
}
|
|
}
|
|
|
|
func TestGenerateUUID(t *testing.T) {
|
|
t.Parallel()
|
|
prev := generateUUID()
|
|
re, err := regexp.Compile("[\\da-f]{8}-[\\da-f]{4}-[\\da-f]{4}-[\\da-f]{4}-[\\da-f]{12}")
|
|
require.NoError(t, err)
|
|
|
|
for i := 0; i < 100; i++ {
|
|
id := generateUUID()
|
|
if prev == id {
|
|
t.Fatalf("Should get a new ID!")
|
|
}
|
|
|
|
matched := re.MatchString(id)
|
|
if !matched {
|
|
t.Fatalf("expected match %s %v %s", id, matched, err)
|
|
}
|
|
}
|
|
}
|
|
|
|
type testServersProvider []metadata.Server
|
|
|
|
func (p testServersProvider) CheckServers(datacenter string, fn func(*metadata.Server) bool) {
|
|
for _, srv := range p {
|
|
// filter these out - now I don't have to modify the tests. Originally the dc filtering
|
|
// happened in the ServersInDCMeetMinimumVersion, now we get a list of servers to check
|
|
// through the routing infrastructure or server lookup which will map a datacenter to a
|
|
// list of metadata.Server structs that are all in that datacenter.
|
|
if srv.Datacenter != datacenter {
|
|
continue
|
|
}
|
|
|
|
if !fn(&srv) {
|
|
return
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestServersInDCMeetMinimumVersion(t *testing.T) {
|
|
t.Parallel()
|
|
makeServer := func(versionStr string, datacenter string) metadata.Server {
|
|
return metadata.Server{
|
|
Name: "foo",
|
|
ShortName: "foo",
|
|
ID: "asdf",
|
|
Port: 10000,
|
|
Expect: 3,
|
|
RaftVersion: 3,
|
|
Status: serf.StatusAlive,
|
|
WanJoinPort: 1234,
|
|
Version: 1,
|
|
Build: *version.Must(version.NewVersion(versionStr)),
|
|
Datacenter: datacenter,
|
|
}
|
|
}
|
|
|
|
cases := []struct {
|
|
servers testServersProvider
|
|
ver *version.Version
|
|
expected bool
|
|
expectedFound bool
|
|
}{
|
|
// One server, meets reqs
|
|
{
|
|
servers: testServersProvider{
|
|
makeServer("0.7.5", "primary"),
|
|
makeServer("0.7.3", "secondary"),
|
|
},
|
|
ver: version.Must(version.NewVersion("0.7.5")),
|
|
expected: true,
|
|
expectedFound: true,
|
|
},
|
|
// One server, doesn't meet reqs
|
|
{
|
|
servers: testServersProvider{
|
|
makeServer("0.7.5", "primary"),
|
|
makeServer("0.8.1", "secondary"),
|
|
},
|
|
ver: version.Must(version.NewVersion("0.8.0")),
|
|
expected: false,
|
|
expectedFound: true,
|
|
},
|
|
// Multiple servers, meets req version
|
|
{
|
|
servers: testServersProvider{
|
|
makeServer("0.7.5", "primary"),
|
|
makeServer("0.8.0", "primary"),
|
|
makeServer("0.7.0", "secondary"),
|
|
},
|
|
ver: version.Must(version.NewVersion("0.7.5")),
|
|
expected: true,
|
|
expectedFound: true,
|
|
},
|
|
// Multiple servers, doesn't meet req version
|
|
{
|
|
servers: testServersProvider{
|
|
makeServer("0.7.5", "primary"),
|
|
makeServer("0.8.0", "primary"),
|
|
makeServer("0.9.1", "secondary"),
|
|
},
|
|
ver: version.Must(version.NewVersion("0.8.0")),
|
|
expected: false,
|
|
expectedFound: true,
|
|
},
|
|
{
|
|
servers: testServersProvider{
|
|
makeServer("0.7.5", "secondary"),
|
|
makeServer("0.8.0", "secondary"),
|
|
makeServer("0.9.1", "secondary"),
|
|
},
|
|
ver: version.Must(version.NewVersion("0.7.0")),
|
|
expected: true,
|
|
expectedFound: false,
|
|
},
|
|
}
|
|
|
|
for _, tc := range cases {
|
|
result, found := ServersInDCMeetMinimumVersion(tc.servers, "primary", tc.ver)
|
|
require.Equal(t, tc.expected, result)
|
|
require.Equal(t, tc.expectedFound, found)
|
|
}
|
|
}
|