...

Source file src/go.etcd.io/etcd/server/v3/etcdserver/cluster_util_test.go

Documentation: go.etcd.io/etcd/server/v3/etcdserver

     1  // Copyright 2015 The etcd Authors
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package etcdserver
    16  
    17  import (
    18  	"reflect"
    19  	"testing"
    20  
    21  	"go.etcd.io/etcd/api/v3/version"
    22  	"go.etcd.io/etcd/client/pkg/v3/types"
    23  
    24  	"github.com/coreos/go-semver/semver"
    25  	"go.uber.org/zap"
    26  )
    27  
    28  var testLogger = zap.NewExample()
    29  
    30  func TestDecideClusterVersion(t *testing.T) {
    31  	tests := []struct {
    32  		vers  map[string]*version.Versions
    33  		wdver *semver.Version
    34  	}{
    35  		{
    36  			map[string]*version.Versions{"a": {Server: "2.0.0"}},
    37  			semver.Must(semver.NewVersion("2.0.0")),
    38  		},
    39  		// unknown
    40  		{
    41  			map[string]*version.Versions{"a": nil},
    42  			nil,
    43  		},
    44  		{
    45  			map[string]*version.Versions{"a": {Server: "2.0.0"}, "b": {Server: "2.1.0"}, "c": {Server: "2.1.0"}},
    46  			semver.Must(semver.NewVersion("2.0.0")),
    47  		},
    48  		{
    49  			map[string]*version.Versions{"a": {Server: "2.1.0"}, "b": {Server: "2.1.0"}, "c": {Server: "2.1.0"}},
    50  			semver.Must(semver.NewVersion("2.1.0")),
    51  		},
    52  		{
    53  			map[string]*version.Versions{"a": nil, "b": {Server: "2.1.0"}, "c": {Server: "2.1.0"}},
    54  			nil,
    55  		},
    56  	}
    57  
    58  	for i, tt := range tests {
    59  		dver := decideClusterVersion(testLogger, tt.vers)
    60  		if !reflect.DeepEqual(dver, tt.wdver) {
    61  			t.Errorf("#%d: ver = %+v, want %+v", i, dver, tt.wdver)
    62  		}
    63  	}
    64  }
    65  
    66  func TestIsCompatibleWithVers(t *testing.T) {
    67  	tests := []struct {
    68  		vers       map[string]*version.Versions
    69  		local      types.ID
    70  		minV, maxV *semver.Version
    71  		wok        bool
    72  	}{
    73  		// too low
    74  		{
    75  			map[string]*version.Versions{
    76  				"a": {Server: "2.0.0", Cluster: "not_decided"},
    77  				"b": {Server: "2.1.0", Cluster: "2.1.0"},
    78  				"c": {Server: "2.1.0", Cluster: "2.1.0"},
    79  			},
    80  			0xa,
    81  			semver.Must(semver.NewVersion("2.0.0")), semver.Must(semver.NewVersion("2.0.0")),
    82  			false,
    83  		},
    84  		{
    85  			map[string]*version.Versions{
    86  				"a": {Server: "2.1.0", Cluster: "not_decided"},
    87  				"b": {Server: "2.1.0", Cluster: "2.1.0"},
    88  				"c": {Server: "2.1.0", Cluster: "2.1.0"},
    89  			},
    90  			0xa,
    91  			semver.Must(semver.NewVersion("2.0.0")), semver.Must(semver.NewVersion("2.1.0")),
    92  			true,
    93  		},
    94  		// too high
    95  		{
    96  			map[string]*version.Versions{
    97  				"a": {Server: "2.2.0", Cluster: "not_decided"},
    98  				"b": {Server: "2.0.0", Cluster: "2.0.0"},
    99  				"c": {Server: "2.0.0", Cluster: "2.0.0"},
   100  			},
   101  			0xa,
   102  			semver.Must(semver.NewVersion("2.1.0")), semver.Must(semver.NewVersion("2.2.0")),
   103  			false,
   104  		},
   105  		// cannot get b's version, expect ok
   106  		{
   107  			map[string]*version.Versions{
   108  				"a": {Server: "2.1.0", Cluster: "not_decided"},
   109  				"b": nil,
   110  				"c": {Server: "2.1.0", Cluster: "2.1.0"},
   111  			},
   112  			0xa,
   113  			semver.Must(semver.NewVersion("2.0.0")), semver.Must(semver.NewVersion("2.1.0")),
   114  			true,
   115  		},
   116  		// cannot get b and c's version, expect not ok
   117  		{
   118  			map[string]*version.Versions{
   119  				"a": {Server: "2.1.0", Cluster: "not_decided"},
   120  				"b": nil,
   121  				"c": nil,
   122  			},
   123  			0xa,
   124  			semver.Must(semver.NewVersion("2.0.0")), semver.Must(semver.NewVersion("2.1.0")),
   125  			false,
   126  		},
   127  	}
   128  
   129  	for i, tt := range tests {
   130  		ok := isCompatibleWithVers(testLogger, tt.vers, tt.local, tt.minV, tt.maxV)
   131  		if ok != tt.wok {
   132  			t.Errorf("#%d: ok = %+v, want %+v", i, ok, tt.wok)
   133  		}
   134  	}
   135  }
   136  
   137  func TestConvertToClusterVersion(t *testing.T) {
   138  	tests := []struct {
   139  		name        string
   140  		inputVerStr string
   141  		expectedVer string
   142  		hasError    bool
   143  	}{
   144  		{
   145  			"Succeeded: Major.Minor.Patch",
   146  			"3.4.2",
   147  			"3.4.0",
   148  			false,
   149  		},
   150  		{
   151  			"Succeeded: Major.Minor",
   152  			"3.4",
   153  			"3.4.0",
   154  			false,
   155  		},
   156  		{
   157  			"Failed: wrong version format",
   158  			"3*.9",
   159  			"",
   160  			true,
   161  		},
   162  	}
   163  	for _, tt := range tests {
   164  		t.Run(tt.name, func(t *testing.T) {
   165  			ver, err := convertToClusterVersion(tt.inputVerStr)
   166  			hasError := err != nil
   167  			if hasError != tt.hasError {
   168  				t.Errorf("Expected error status is %v; Got %v", tt.hasError, err)
   169  			}
   170  			if tt.hasError {
   171  				return
   172  			}
   173  			if ver == nil || tt.expectedVer != ver.String() {
   174  				t.Errorf("Expected output cluster version is %v; Got %v", tt.expectedVer, ver)
   175  			}
   176  		})
   177  	}
   178  }
   179  
   180  func TestDecideAllowedVersionRange(t *testing.T) {
   181  	minClusterV := semver.Must(semver.NewVersion(version.MinClusterVersion))
   182  	localV := semver.Must(semver.NewVersion(version.Version))
   183  	localV = &semver.Version{Major: localV.Major, Minor: localV.Minor}
   184  
   185  	tests := []struct {
   186  		name             string
   187  		downgradeEnabled bool
   188  		expectedMinV     *semver.Version
   189  		expectedMaxV     *semver.Version
   190  	}{
   191  		{
   192  			"When cluster enables downgrade",
   193  			true,
   194  			&semver.Version{Major: localV.Major, Minor: localV.Minor + 1},
   195  			&semver.Version{Major: localV.Major, Minor: localV.Minor + 1},
   196  		},
   197  		{
   198  			"When cluster disables downgrade",
   199  			false,
   200  			minClusterV,
   201  			localV,
   202  		},
   203  	}
   204  
   205  	for _, tt := range tests {
   206  		t.Run(tt.name, func(t *testing.T) {
   207  			minV, maxV := allowedVersionRange(tt.downgradeEnabled)
   208  			if !minV.Equal(*tt.expectedMinV) {
   209  				t.Errorf("Expected minV is %v; Got %v", tt.expectedMinV.String(), minV.String())
   210  			}
   211  
   212  			if !maxV.Equal(*tt.expectedMaxV) {
   213  				t.Errorf("Expected maxV is %v; Got %v", tt.expectedMaxV.String(), maxV.String())
   214  			}
   215  		})
   216  	}
   217  }
   218  
   219  func TestIsMatchedVersions(t *testing.T) {
   220  	tests := []struct {
   221  		name             string
   222  		targetVersion    *semver.Version
   223  		versionMap       map[string]*version.Versions
   224  		expectedFinished bool
   225  	}{
   226  		{
   227  			"When downgrade finished",
   228  			&semver.Version{Major: 3, Minor: 4},
   229  			map[string]*version.Versions{
   230  				"mem1": {Server: "3.4.1", Cluster: "3.4.0"},
   231  				"mem2": {Server: "3.4.2-pre", Cluster: "3.4.0"},
   232  				"mem3": {Server: "3.4.2", Cluster: "3.4.0"},
   233  			},
   234  			true,
   235  		},
   236  		{
   237  			"When cannot parse peer version",
   238  			&semver.Version{Major: 3, Minor: 4},
   239  			map[string]*version.Versions{
   240  				"mem1": {Server: "3.4.1", Cluster: "3.4"},
   241  				"mem2": {Server: "3.4.2-pre", Cluster: "3.4.0"},
   242  				"mem3": {Server: "3.4.2", Cluster: "3.4.0"},
   243  			},
   244  			false,
   245  		},
   246  		{
   247  			"When downgrade not finished",
   248  			&semver.Version{Major: 3, Minor: 4},
   249  			map[string]*version.Versions{
   250  				"mem1": {Server: "3.4.1", Cluster: "3.4.0"},
   251  				"mem2": {Server: "3.4.2-pre", Cluster: "3.4.0"},
   252  				"mem3": {Server: "3.5.2", Cluster: "3.5.0"},
   253  			},
   254  			false,
   255  		},
   256  	}
   257  
   258  	for _, tt := range tests {
   259  		t.Run(tt.name, func(t *testing.T) {
   260  			actual := isMatchedVersions(zap.NewNop(), tt.targetVersion, tt.versionMap)
   261  			if actual != tt.expectedFinished {
   262  				t.Errorf("expected downgrade finished is %v; got %v", tt.expectedFinished, actual)
   263  			}
   264  		})
   265  	}
   266  }
   267  

View as plain text