server: Cover monitor with upgrade unit tests

This commit is contained in:
Marek Siarkowicz
2021-10-04 15:32:42 +02:00
parent b571ec5e67
commit 2de36c0596
4 changed files with 359 additions and 16 deletions

View File

@ -5,15 +5,15 @@ import (
"testing"
"github.com/coreos/go-semver/semver"
"go.uber.org/zap"
"github.com/stretchr/testify/assert"
"go.uber.org/zap/zaptest"
"go.etcd.io/etcd/api/v3/version"
"go.etcd.io/etcd/server/v3/etcdserver/api/membership"
)
var testLogger = zap.NewExample()
var (
V3_0 = semver.Version{Major: 3, Minor: 0}
V3_5 = semver.Version{Major: 3, Minor: 5}
V3_6 = semver.Version{Major: 3, Minor: 6}
)
@ -47,8 +47,8 @@ func TestDecideClusterVersion(t *testing.T) {
}
for i, tt := range tests {
monitor := NewMonitor(testLogger, &storageMock{
versions: tt.vers,
monitor := NewMonitor(zaptest.NewLogger(t), &storageMock{
memberVersions: tt.vers,
})
dver := monitor.decideClusterVersion()
if !reflect.DeepEqual(dver, tt.wdver) {
@ -97,7 +97,7 @@ func TestDecideStorageVersion(t *testing.T) {
clusterVersion: tt.clusterVersion,
storageVersion: tt.storageVersion,
}
monitor := NewMonitor(testLogger, s)
monitor := NewMonitor(zaptest.NewLogger(t), s)
monitor.UpdateStorageVersionIfNeeded()
if !reflect.DeepEqual(s.storageVersion, tt.expectStorageVersion) {
t.Errorf("Unexpected storage version value, got = %+v, want %+v", s.storageVersion, tt.expectStorageVersion)
@ -147,8 +147,8 @@ func TestVersionMatchTarget(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
monitor := NewMonitor(testLogger, &storageMock{
versions: tt.versionMap,
monitor := NewMonitor(zaptest.NewLogger(t), &storageMock{
memberVersions: tt.versionMap,
})
actual := monitor.versionsMatchTarget(tt.targetVersion)
if actual != tt.expectedFinished {
@ -158,8 +158,176 @@ func TestVersionMatchTarget(t *testing.T) {
}
}
func TestUpdateClusterVersionIfNeeded(t *testing.T) {
tests := []struct {
name string
clusterVersion *semver.Version
memberVersions map[string]*version.Versions
downgrade *membership.DowngradeInfo
expectClusterVersion *semver.Version
}{
{
name: "Default to 3.0 if there are no members",
expectClusterVersion: &V3_0,
},
{
name: "Should pick lowest server version from members",
memberVersions: map[string]*version.Versions{
"a": {Cluster: "3.7.0", Server: "3.6.0"},
"b": {Cluster: "3.4.0", Server: "3.5.0"},
},
expectClusterVersion: &V3_5,
},
{
name: "Sets minimal version when member has broken version",
memberVersions: map[string]*version.Versions{
"a": {Cluster: "3.7.0", Server: "3.6.0"},
"b": {Cluster: "xxxx", Server: "yyyy"},
},
expectClusterVersion: &V3_0,
},
{
name: "Should pick lowest server version from members (cv already set)",
memberVersions: map[string]*version.Versions{
"a": {Cluster: "3.7.0", Server: "3.6.0"},
"b": {Cluster: "3.4.0", Server: "3.5.0"},
},
clusterVersion: &V3_5,
expectClusterVersion: &V3_5,
},
{
name: "Should upgrade cluster version if all members have upgraded (have higher server version)",
memberVersions: map[string]*version.Versions{
"a": {Cluster: "3.5.0", Server: "3.6.0"},
"b": {Cluster: "3.5.0", Server: "3.6.0"},
},
clusterVersion: &V3_5,
expectClusterVersion: &V3_6,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
s := &storageMock{
clusterVersion: tt.clusterVersion,
memberVersions: tt.memberVersions,
downgradeInfo: tt.downgrade,
}
monitor := NewMonitor(zaptest.NewLogger(t), s)
// Run multiple times to ensure that results are stable
for i := 0; i < 3; i++ {
monitor.UpdateClusterVersionIfNeeded()
assert.Equal(t, tt.expectClusterVersion, s.clusterVersion)
}
})
}
}
func TestCancelDowngradeIfNeeded(t *testing.T) {
tests := []struct {
name string
memberVersions map[string]*version.Versions
downgrade *membership.DowngradeInfo
expectDowngrade *membership.DowngradeInfo
}{
{
name: "No action if there no downgrade in progress",
},
{
name: "Cancel downgrade if there are no members",
downgrade: &membership.DowngradeInfo{TargetVersion: "3.5.0", Enabled: true},
expectDowngrade: nil,
},
// Next entries go through all states that should happen during downgrade
{
name: "No action if downgrade was not started",
memberVersions: map[string]*version.Versions{
"a": {Cluster: "3.6.0", Server: "3.6.1"},
"b": {Cluster: "3.6.0", Server: "3.6.2"},
},
},
{
name: "Cancel downgrade if all members have downgraded",
memberVersions: map[string]*version.Versions{
"a": {Cluster: "3.5.0", Server: "3.5.1"},
"b": {Cluster: "3.5.0", Server: "3.5.2"},
},
downgrade: &membership.DowngradeInfo{TargetVersion: "3.5.0", Enabled: true},
expectDowngrade: nil,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
s := &storageMock{
memberVersions: tt.memberVersions,
downgradeInfo: tt.downgrade,
}
monitor := NewMonitor(zaptest.NewLogger(t), s)
// Run multiple times to ensure that results are stable
for i := 0; i < 3; i++ {
monitor.CancelDowngradeIfNeeded()
assert.Equal(t, tt.expectDowngrade, s.downgradeInfo)
}
})
}
}
func TestUpdateStorageVersionIfNeeded(t *testing.T) {
tests := []struct {
name string
clusterVersion *semver.Version
storageVersion *semver.Version
expectStorageVersion *semver.Version
}{
{
name: "No action if cluster version is nil",
},
{
name: "Should set storage version if cluster version is set",
clusterVersion: &V3_5,
expectStorageVersion: &V3_5,
},
{
name: "No action if storage version was already set",
storageVersion: &V3_5,
expectStorageVersion: &V3_5,
},
{
name: "No action if storage version equals cluster version",
clusterVersion: &V3_5,
storageVersion: &V3_5,
expectStorageVersion: &V3_5,
},
{
name: "Should set storage version to cluster version",
clusterVersion: &V3_6,
storageVersion: &V3_5,
expectStorageVersion: &V3_6,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
s := &storageMock{
clusterVersion: tt.clusterVersion,
storageVersion: tt.storageVersion,
}
monitor := NewMonitor(zaptest.NewLogger(t), s)
// Run multiple times to ensure that results are stable
for i := 0; i < 3; i++ {
monitor.UpdateStorageVersionIfNeeded()
assert.Equal(t, tt.expectStorageVersion, s.storageVersion)
}
})
}
}
type storageMock struct {
versions map[string]*version.Versions
memberVersions map[string]*version.Versions
clusterVersion *semver.Version
storageVersion *semver.Version
downgradeInfo *membership.DowngradeInfo
@ -184,8 +352,8 @@ func (s *storageMock) GetDowngradeInfo() *membership.DowngradeInfo {
return s.downgradeInfo
}
func (s *storageMock) GetVersions() map[string]*version.Versions {
return s.versions
func (s *storageMock) GetMembersVersions() map[string]*version.Versions {
return s.memberVersions
}
func (s *storageMock) GetStorageVersion() *semver.Version {