knative.dev/pkg@v0.0.0-20260602142205-ac97e43f6622/test/upgrade/testing_operations_test.go (about) 1 /* 2 Copyright 2020 The Knative Authors 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package upgrade_test 18 19 import ( 20 "fmt" 21 "testing" 22 23 "go.uber.org/zap" 24 "go.uber.org/zap/zapcore" 25 26 "knative.dev/pkg/test/upgrade" 27 ) 28 29 const ( 30 failureTestingMessage = "This error is expected to be seen. Upgrade suite should fail." 31 ) 32 33 func newConfig(t *testing.T) (upgrade.Configuration, fmt.Stringer) { 34 buf := threadSafeBuffer{} 35 cfg := zap.NewDevelopmentConfig() 36 cfg.EncoderConfig.TimeKey = "" 37 cfg.EncoderConfig.CallerKey = "" 38 syncedBuf := zapcore.AddSync(&buf) 39 logConfig := upgrade.LogConfig{ 40 Options: []zap.Option{ 41 zap.WrapCore(func(core zapcore.Core) zapcore.Core { 42 return zapcore.NewCore( 43 zapcore.NewConsoleEncoder(cfg.EncoderConfig), 44 zapcore.NewMultiWriteSyncer(syncedBuf), cfg.Level) 45 }), 46 zap.ErrorOutput(syncedBuf), 47 }, 48 } 49 c := upgrade.Configuration{ 50 T: t, 51 LogConfig: logConfig, 52 } 53 return c, &buf 54 } 55 56 func createSteps(s upgrade.Suite) []*step { 57 continualTestsGeneralized := generalizeOpsFromBg(s.Tests.Continual) 58 return []*step{{ 59 messages: messageFormatters.baseInstall, 60 ops: generalizeOps(s.Installations.Base), 61 updateSuite: func(ops operations, s *upgrade.Suite) { 62 s.Installations.Base = ops.asOperations() 63 }, 64 }, { 65 messages: messageFormatters.preUpgrade, 66 ops: generalizeOps(s.Tests.PreUpgrade), 67 updateSuite: func(ops operations, s *upgrade.Suite) { 68 s.Tests.PreUpgrade = ops.asOperations() 69 }, 70 }, { 71 messages: messageFormatters.startContinual, 72 ops: continualTestsGeneralized, 73 updateSuite: func(ops operations, s *upgrade.Suite) { 74 s.Tests.Continual = ops.asBackgroundOperation() 75 }, 76 }, { 77 messages: messageFormatters.upgrade, 78 ops: generalizeOps(s.Installations.UpgradeWith), 79 updateSuite: func(ops operations, s *upgrade.Suite) { 80 s.Installations.UpgradeWith = ops.asOperations() 81 }, 82 }, { 83 messages: messageFormatters.postUpgrade, 84 ops: generalizeOps(s.Tests.PostUpgrade), 85 updateSuite: func(ops operations, s *upgrade.Suite) { 86 s.Tests.PostUpgrade = ops.asOperations() 87 }, 88 }, { 89 messages: messageFormatters.downgrade, 90 ops: generalizeOps(s.Installations.DowngradeWith), 91 updateSuite: func(ops operations, s *upgrade.Suite) { 92 s.Installations.DowngradeWith = ops.asOperations() 93 }, 94 }, { 95 messages: messageFormatters.postDowngrade, 96 ops: generalizeOps(s.Tests.PostDowngrade), 97 updateSuite: func(ops operations, s *upgrade.Suite) { 98 s.Tests.PostDowngrade = ops.asOperations() 99 }, 100 }} 101 } 102 103 func expectedTexts(s upgrade.Suite, fp failurePoint) texts { 104 steps := createSteps(s) 105 tt := texts{elms: nil} 106 for i, st := range steps { 107 stepIdx := i + 1 108 if st.ops.length() == 0 { 109 tt.append(st.skipped(stepIdx)) 110 } else { 111 tt.append(st.starting(stepIdx, st.ops.length())) 112 for j, op := range st.ops.ops { 113 elemIdx := j + 1 114 tt.append(st.element(stepIdx, elemIdx, op.Name())) 115 if fp.step == stepIdx && fp.element == elemIdx { 116 return tt 117 } 118 } 119 } 120 } 121 return tt 122 } 123 124 func generalizeOps(ops []upgrade.Operation) operations { 125 gen := make([]*operation, len(ops)) 126 for idx, op := range ops { 127 gen[idx] = &operation{op: op} 128 } 129 return operations{ops: gen} 130 } 131 132 func generalizeOpsFromBg(ops []upgrade.BackgroundOperation) operations { 133 gen := make([]*operation, len(ops)) 134 for idx, op := range ops { 135 gen[idx] = &operation{bg: op} 136 } 137 return operations{ops: gen} 138 } 139 140 func createMessages(mf formats) messages { 141 return messages{ 142 skipped: func(args ...interface{}) string { 143 empty := "" 144 if mf.skipped == empty { 145 return empty 146 } 147 return fmt.Sprintf(mf.skipped, args...) 148 }, 149 starting: func(args ...interface{}) string { 150 return fmt.Sprintf(mf.starting, args...) 151 }, 152 element: func(args ...interface{}) string { 153 return fmt.Sprintf(mf.element, args...) 154 }, 155 } 156 } 157 158 func (tt *texts) append(messages ...string) { 159 for _, msg := range messages { 160 if msg == "" { 161 continue 162 } 163 tt.elms = append(tt.elms, msg) 164 } 165 } 166 167 func completeSuite() upgrade.Suite { 168 serving := servingComponent() 169 eventing := eventingComponent() 170 return upgrade.Suite{ 171 Tests: upgrade.Tests{ 172 PreUpgrade: []upgrade.Operation{ 173 serving.tests.preUpgrade, eventing.tests.preUpgrade, 174 }, 175 PostUpgrade: []upgrade.Operation{ 176 serving.tests.postUpgrade, eventing.tests.postUpgrade, 177 }, 178 PostDowngrade: []upgrade.Operation{ 179 serving.tests.postDowngrade, eventing.tests.postDowngrade, 180 }, 181 Continual: []upgrade.BackgroundOperation{ 182 serving.tests.continual, 183 }, 184 }, 185 Installations: upgrade.Installations{ 186 Base: []upgrade.Operation{ 187 serving.installs.stable, eventing.installs.stable, 188 }, 189 UpgradeWith: []upgrade.Operation{ 190 serving.installs.head, eventing.installs.head, 191 }, 192 DowngradeWith: []upgrade.Operation{ 193 serving.installs.stable, eventing.installs.stable, 194 }, 195 }, 196 } 197 } 198 199 func completeSuiteExampleWithFailures(fp failurePoint) upgrade.Suite { 200 return enrichSuiteWithFailures(completeSuite(), fp) 201 } 202 203 func emptySuiteExample() upgrade.Suite { 204 return upgrade.Suite{ 205 Tests: upgrade.Tests{}, 206 Installations: upgrade.Installations{}, 207 } 208 } 209 210 func enrichSuiteWithFailures(suite upgrade.Suite, fp failurePoint) upgrade.Suite { 211 steps := createSteps(suite) 212 for i, st := range steps { 213 for j, op := range st.ops.ops { 214 if fp.step == i+1 && fp.element == j+1 { 215 op.fail(fp.step == 3) 216 } 217 } 218 } 219 return recreateSuite(steps) 220 } 221 222 func recreateSuite(steps []*step) upgrade.Suite { 223 suite := &upgrade.Suite{ 224 Tests: upgrade.Tests{}, 225 Installations: upgrade.Installations{}, 226 } 227 for _, st := range steps { 228 st.updateSuite(st.ops, suite) 229 } 230 return *suite 231 } 232 233 func (o operation) Name() string { 234 if o.op != nil { 235 return o.op.Name() 236 } 237 return o.bg.Name() 238 } 239 240 func (o *operation) fail(setupFail bool) { 241 testName := "FailingOf" + o.Name() 242 if o.op != nil { 243 prev := o.op 244 o.op = upgrade.NewOperation(testName, func(c upgrade.Context) { 245 handler := prev.Handler() 246 handler(c) 247 c.T.Error(failureTestingMessage) 248 c.Log.Error(failureTestingMessage) 249 }) 250 } else { 251 prev := o.bg 252 o.bg = upgrade.NewBackgroundOperation(testName, func(c upgrade.Context) { 253 setup := prev.Setup() 254 setup(c) 255 if setupFail { 256 c.T.Error(failureTestingMessage) 257 c.Log.Error(failureTestingMessage) 258 } 259 }, func(bc upgrade.BackgroundContext) { 260 upgrade.WaitForStopEvent(bc, upgrade.WaitForStopEventConfiguration{ 261 Name: testName, 262 OnStop: func() { 263 if !setupFail { 264 bc.T.Error(failureTestingMessage) 265 bc.Log.Error(failureTestingMessage) 266 } 267 }, 268 OnWait: func(bc upgrade.BackgroundContext, self upgrade.WaitForStopEventConfiguration) { 269 bc.Log.Debugf("%s - probing functionality...", self.Name) 270 }, 271 WaitTime: shortWait, 272 }) 273 }) 274 } 275 } 276 277 func (o operations) length() int { 278 return len(o.ops) 279 } 280 281 func (o operations) asOperations() []upgrade.Operation { 282 ops := make([]upgrade.Operation, o.length()) 283 for i, op := range o.ops { 284 ops[i] = op.op 285 } 286 return ops 287 } 288 289 func (o operations) asBackgroundOperation() []upgrade.BackgroundOperation { 290 ops := make([]upgrade.BackgroundOperation, o.length()) 291 for i, op := range o.ops { 292 ops[i] = op.bg 293 } 294 return ops 295 }