mirror of
https://github.com/etcd-io/etcd.git
synced 2024-09-27 06:25:44 +00:00
288 lines
7.3 KiB
Go
288 lines
7.3 KiB
Go
// Copyright 2021 The etcd Authors
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
package wal
|
|
|
|
import (
|
|
"fmt"
|
|
"testing"
|
|
|
|
"github.com/coreos/go-semver/semver"
|
|
"github.com/golang/protobuf/proto"
|
|
"github.com/stretchr/testify/assert"
|
|
"google.golang.org/protobuf/reflect/protoreflect"
|
|
|
|
"go.etcd.io/etcd/api/v3/etcdserverpb"
|
|
"go.etcd.io/etcd/api/v3/membershippb"
|
|
"go.etcd.io/etcd/api/v3/version"
|
|
"go.etcd.io/etcd/pkg/v3/pbutil"
|
|
"go.etcd.io/raft/v3/raftpb"
|
|
)
|
|
|
|
func TestEtcdVersionFromEntry(t *testing.T) {
|
|
raftReq := etcdserverpb.InternalRaftRequest{Header: &etcdserverpb.RequestHeader{AuthRevision: 1}}
|
|
normalRequestData := pbutil.MustMarshal(&raftReq)
|
|
|
|
clusterVersionV3_6Req := etcdserverpb.InternalRaftRequest{ClusterVersionSet: &membershippb.ClusterVersionSetRequest{Ver: "3.6.0"}}
|
|
clusterVersionV3_6Data := pbutil.MustMarshal(&clusterVersionV3_6Req)
|
|
|
|
confChange := raftpb.ConfChange{Type: raftpb.ConfChangeAddLearnerNode}
|
|
confChangeData := pbutil.MustMarshal(&confChange)
|
|
|
|
confChangeV2 := raftpb.ConfChangeV2{Transition: raftpb.ConfChangeTransitionJointExplicit}
|
|
confChangeV2Data := pbutil.MustMarshal(&confChangeV2)
|
|
|
|
tcs := []struct {
|
|
name string
|
|
input raftpb.Entry
|
|
expect *semver.Version
|
|
}{
|
|
{
|
|
name: "Using RequestHeader AuthRevision in NormalEntry implies v3.1",
|
|
input: raftpb.Entry{
|
|
Term: 1,
|
|
Index: 2,
|
|
Type: raftpb.EntryNormal,
|
|
Data: normalRequestData,
|
|
},
|
|
expect: &version.V3_1,
|
|
},
|
|
{
|
|
name: "Setting cluster version implies version within",
|
|
input: raftpb.Entry{
|
|
Term: 1,
|
|
Index: 2,
|
|
Type: raftpb.EntryNormal,
|
|
Data: clusterVersionV3_6Data,
|
|
},
|
|
expect: &version.V3_6,
|
|
},
|
|
{
|
|
name: "Using ConfigChange implies v3.0",
|
|
input: raftpb.Entry{
|
|
Term: 1,
|
|
Index: 2,
|
|
Type: raftpb.EntryConfChange,
|
|
Data: confChangeData,
|
|
},
|
|
expect: &version.V3_0,
|
|
},
|
|
{
|
|
name: "Using ConfigChangeV2 implies v3.4",
|
|
input: raftpb.Entry{
|
|
Term: 1,
|
|
Index: 2,
|
|
Type: raftpb.EntryConfChangeV2,
|
|
Data: confChangeV2Data,
|
|
},
|
|
expect: &version.V3_4,
|
|
},
|
|
}
|
|
for _, tc := range tcs {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
var maxVer *semver.Version
|
|
err := visitEntry(tc.input, func(path protoreflect.FullName, ver *semver.Version) error {
|
|
maxVer = maxVersion(maxVer, ver)
|
|
return nil
|
|
})
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, tc.expect, maxVer)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestEtcdVersionFromMessage(t *testing.T) {
|
|
tcs := []struct {
|
|
name string
|
|
input proto.Message
|
|
expect *semver.Version
|
|
}{
|
|
{
|
|
name: "Empty RequestHeader impies v3.0",
|
|
input: &etcdserverpb.RequestHeader{},
|
|
expect: &version.V3_0,
|
|
},
|
|
{
|
|
name: "RequestHeader AuthRevision field set implies v3.5",
|
|
input: &etcdserverpb.RequestHeader{AuthRevision: 1},
|
|
expect: &version.V3_1,
|
|
},
|
|
{
|
|
name: "RequestHeader Username set implies v3.0",
|
|
input: &etcdserverpb.RequestHeader{Username: "Alice"},
|
|
expect: &version.V3_0,
|
|
},
|
|
{
|
|
name: "When two fields are set take higher version",
|
|
input: &etcdserverpb.RequestHeader{AuthRevision: 1, Username: "Alice"},
|
|
expect: &version.V3_1,
|
|
},
|
|
{
|
|
name: "Setting a RequestHeader AuthRevision in subfield implies v3.1",
|
|
input: &etcdserverpb.InternalRaftRequest{Header: &etcdserverpb.RequestHeader{AuthRevision: 1}},
|
|
expect: &version.V3_1,
|
|
},
|
|
{
|
|
name: "Setting a DowngradeInfoSetRequest implies v3.5",
|
|
input: &etcdserverpb.InternalRaftRequest{DowngradeInfoSet: &membershippb.DowngradeInfoSetRequest{}},
|
|
expect: &version.V3_5,
|
|
},
|
|
{
|
|
name: "Enum CompareResult set to EQUAL implies v3.0",
|
|
input: &etcdserverpb.Compare{Result: etcdserverpb.Compare_EQUAL},
|
|
expect: &version.V3_0,
|
|
},
|
|
{
|
|
name: "Enum CompareResult set to NOT_EQUAL implies v3.1",
|
|
input: &etcdserverpb.Compare{Result: etcdserverpb.Compare_NOT_EQUAL},
|
|
expect: &version.V3_1,
|
|
},
|
|
{
|
|
name: "Oneof Compare version set implies v3.1",
|
|
input: &etcdserverpb.Compare{TargetUnion: &etcdserverpb.Compare_Version{}},
|
|
expect: &version.V3_0,
|
|
},
|
|
{
|
|
name: "Oneof Compare lease set implies v3.3",
|
|
input: &etcdserverpb.Compare{TargetUnion: &etcdserverpb.Compare_Lease{}},
|
|
expect: &version.V3_3,
|
|
},
|
|
}
|
|
for _, tc := range tcs {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
var maxVer *semver.Version
|
|
err := visitMessage(proto.MessageReflect(tc.input), func(path protoreflect.FullName, ver *semver.Version) error {
|
|
maxVer = maxVersion(maxVer, ver)
|
|
return nil
|
|
})
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, tc.expect, maxVer)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestEtcdVersionFromFieldOptionsString(t *testing.T) {
|
|
tcs := []struct {
|
|
input string
|
|
expect *semver.Version
|
|
}{
|
|
{
|
|
input: "65001:0",
|
|
},
|
|
{
|
|
input: `65001:0 65004:"NodeID"`,
|
|
},
|
|
{
|
|
input: `[versionpb.XXX]:"3.5"`,
|
|
},
|
|
{
|
|
input: `[versionpb.etcd_version_msg]:"3.5"`,
|
|
expect: &version.V3_5,
|
|
},
|
|
{
|
|
input: `[versionpb.etcd_version_enum]:"3.5"`,
|
|
expect: &version.V3_5,
|
|
},
|
|
{
|
|
input: `[versionpb.etcd_version_field]:"3.5"`,
|
|
expect: &version.V3_5,
|
|
},
|
|
{
|
|
input: `[versionpb.etcd_version_enum_value]:"3.5"`,
|
|
expect: &version.V3_5,
|
|
},
|
|
{
|
|
input: `65001:0 [versionpb.etcd_version_msg]:"3.5"`,
|
|
expect: &version.V3_5,
|
|
},
|
|
{
|
|
input: `65004:"NodeID" [versionpb.etcd_version_msg]:"3.5"`,
|
|
expect: &version.V3_5,
|
|
},
|
|
{
|
|
input: `65004:"NodeID" [versionpb.etcd_version_enum]:"3.5"`,
|
|
expect: &version.V3_5,
|
|
},
|
|
{
|
|
input: `[versionpb.other_field]:"NodeID" [versionpb.etcd_version_msg]:"3.5"`,
|
|
expect: &version.V3_5,
|
|
},
|
|
{
|
|
input: `[versionpb.etcd_version_msg]:"3.5" 65001:0`,
|
|
expect: &version.V3_5,
|
|
},
|
|
{
|
|
input: `[versionpb.etcd_version_msg]:"3.5" 65004:"NodeID"`,
|
|
expect: &version.V3_5,
|
|
},
|
|
{
|
|
input: `[versionpb.etcd_version_msg]:"3.5" [versionpb.other_field]:"NodeID"`,
|
|
expect: &version.V3_5,
|
|
},
|
|
{
|
|
input: `[versionpb.other_field]:"NodeID" [versionpb.etcd_version_msg]:"3.5" [versionpb.another_field]:"NodeID"`,
|
|
expect: &version.V3_5,
|
|
},
|
|
{
|
|
input: `65001:0 [versionpb.etcd_version_msg]:"3.5" 65001:0"`,
|
|
expect: &version.V3_5,
|
|
},
|
|
}
|
|
for _, tc := range tcs {
|
|
t.Run(tc.input, func(t *testing.T) {
|
|
ver, err := etcdVersionFromOptionsString(tc.input)
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, ver, tc.expect)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestMaxVersion(t *testing.T) {
|
|
tcs := []struct {
|
|
a, b, expect *semver.Version
|
|
}{
|
|
{
|
|
a: nil,
|
|
b: nil,
|
|
expect: nil,
|
|
},
|
|
{
|
|
a: &version.V3_5,
|
|
b: nil,
|
|
expect: &version.V3_5,
|
|
},
|
|
{
|
|
a: nil,
|
|
b: &version.V3_5,
|
|
expect: &version.V3_5,
|
|
},
|
|
{
|
|
a: &version.V3_6,
|
|
b: &version.V3_5,
|
|
expect: &version.V3_6,
|
|
},
|
|
{
|
|
a: &version.V3_5,
|
|
b: &version.V3_6,
|
|
expect: &version.V3_6,
|
|
},
|
|
}
|
|
for _, tc := range tcs {
|
|
t.Run(fmt.Sprintf("%v %v %v", tc.a, tc.b, tc.expect), func(t *testing.T) {
|
|
got := maxVersion(tc.a, tc.b)
|
|
assert.Equal(t, got, tc.expect)
|
|
})
|
|
}
|
|
}
|