1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package membership
16
17 import (
18 "bytes"
19 "fmt"
20 "io/ioutil"
21 "os"
22 "os/exec"
23 "path/filepath"
24 "strconv"
25 "testing"
26
27 "github.com/coreos/go-semver/semver"
28 "go.etcd.io/etcd/api/v3/version"
29 "go.uber.org/zap"
30 )
31
32 func TestMustDetectDowngrade(t *testing.T) {
33 lv := semver.Must(semver.NewVersion(version.Version))
34 lv = &semver.Version{Major: lv.Major, Minor: lv.Minor}
35 oneMinorHigher := &semver.Version{Major: lv.Major, Minor: lv.Minor + 1}
36 oneMinorLower := &semver.Version{Major: lv.Major, Minor: lv.Minor - 1}
37 downgradeEnabledHigherVersion := &DowngradeInfo{Enabled: true, TargetVersion: oneMinorHigher.String()}
38 downgradeEnabledEqualVersion := &DowngradeInfo{Enabled: true, TargetVersion: lv.String()}
39 downgradeEnabledLowerVersion := &DowngradeInfo{Enabled: true, TargetVersion: oneMinorLower.String()}
40 downgradeDisabled := &DowngradeInfo{Enabled: false}
41
42 tests := []struct {
43 name string
44 clusterVersion *semver.Version
45 downgrade *DowngradeInfo
46 success bool
47 message string
48 }{
49 {
50 "Succeeded when downgrade is disabled and cluster version is nil",
51 nil,
52 downgradeDisabled,
53 true,
54 "",
55 },
56 {
57 "Succeeded when downgrade is disabled and cluster version is one minor lower",
58 oneMinorLower,
59 downgradeDisabled,
60 true,
61 "",
62 },
63 {
64 "Succeeded when downgrade is disabled and cluster version is server version",
65 lv,
66 downgradeDisabled,
67 true,
68 "",
69 },
70 {
71 "Failed when downgrade is disabled and server version is lower than determined cluster version ",
72 oneMinorHigher,
73 downgradeDisabled,
74 false,
75 "invalid downgrade; server version is lower than determined cluster version",
76 },
77 {
78 "Succeeded when downgrade is enabled and cluster version is nil",
79 nil,
80 downgradeEnabledEqualVersion,
81 true,
82 "",
83 },
84 {
85 "Failed when downgrade is enabled and server version is target version",
86 lv,
87 downgradeEnabledEqualVersion,
88 true,
89 "cluster is downgrading to target version",
90 },
91 {
92 "Succeeded when downgrade to lower version and server version is cluster version ",
93 lv,
94 downgradeEnabledLowerVersion,
95 false,
96 "invalid downgrade; server version is not allowed to join when downgrade is enabled",
97 },
98 {
99 "Failed when downgrade is enabled and local version is out of range and cluster version is nil",
100 nil,
101 downgradeEnabledHigherVersion,
102 false,
103 "invalid downgrade; server version is not allowed to join when downgrade is enabled",
104 },
105
106 {
107 "Failed when downgrade is enabled and local version is out of range",
108 lv,
109 downgradeEnabledHigherVersion,
110 false,
111 "invalid downgrade; server version is not allowed to join when downgrade is enabled",
112 },
113 }
114
115 if os.Getenv("DETECT_DOWNGRADE") != "" {
116 i := os.Getenv("DETECT_DOWNGRADE")
117 iint, _ := strconv.Atoi(i)
118 logPath := filepath.Join(os.TempDir(), fmt.Sprintf("test-log-must-detect-downgrade-%v", iint))
119
120 lcfg := zap.NewProductionConfig()
121 lcfg.OutputPaths = []string{logPath}
122 lcfg.ErrorOutputPaths = []string{logPath}
123 lg, _ := lcfg.Build()
124
125 mustDetectDowngrade(lg, tests[iint].clusterVersion, tests[iint].downgrade)
126 return
127 }
128
129 for i, tt := range tests {
130 t.Run(tt.name, func(t *testing.T) {
131 logPath := filepath.Join(os.TempDir(), fmt.Sprintf("test-log-must-detect-downgrade-%d", i))
132 t.Log(logPath)
133 defer os.RemoveAll(logPath)
134
135 cmd := exec.Command(os.Args[0], "-test.run=TestMustDetectDowngrade")
136 cmd.Env = append(os.Environ(), fmt.Sprintf("DETECT_DOWNGRADE=%d", i))
137 if err := cmd.Start(); err != nil {
138 t.Fatal(err)
139 }
140
141 errCmd := cmd.Wait()
142
143 data, err := ioutil.ReadFile(logPath)
144 if err == nil {
145 if !bytes.Contains(data, []byte(tt.message)) {
146 t.Errorf("Expected to find %v in log", tt.message)
147 }
148 } else {
149 t.Fatal(err)
150 }
151
152 if !tt.success {
153 e, ok := errCmd.(*exec.ExitError)
154 if !ok || e.Success() {
155 t.Errorf("Expected exit with status 1; Got %v", err)
156 }
157 }
158
159 if tt.success && errCmd != nil {
160 t.Errorf("Expected not failure; Got %v", errCmd)
161 }
162 })
163 }
164 }
165
166 func TestIsValidDowngrade(t *testing.T) {
167 tests := []struct {
168 name string
169 verFrom string
170 verTo string
171 result bool
172 }{
173 {
174 "Valid downgrade",
175 "3.5.0",
176 "3.4.0",
177 true,
178 },
179 {
180 "Invalid downgrade",
181 "3.5.2",
182 "3.3.0",
183 false,
184 },
185 }
186 for _, tt := range tests {
187 t.Run(tt.name, func(t *testing.T) {
188 res := isValidDowngrade(
189 semver.Must(semver.NewVersion(tt.verFrom)), semver.Must(semver.NewVersion(tt.verTo)))
190 if res != tt.result {
191 t.Errorf("Expected downgrade valid is %v; Got %v", tt.result, res)
192 }
193 })
194 }
195 }
196
View as plain text