github.com/munnerz/test-infra@v0.0.0-20190108210205-ce3d181dc989/kubetest/process/process_test.go (about) 1 /* 2 Copyright 2017 The Kubernetes 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 process 18 19 import ( 20 "errors" 21 "log" 22 "os/exec" 23 "strconv" 24 "strings" 25 "testing" 26 "time" 27 28 "k8s.io/test-infra/kubetest/util" 29 ) 30 31 var suite util.TestSuite 32 33 func TestXMLWrap(t *testing.T) { 34 cases := []struct { 35 name string 36 interrupted bool 37 shouldInterrupt bool 38 err string 39 expectSkipped bool 40 expectError bool 41 }{ 42 { 43 name: "xmlWrap can pass", 44 }, 45 { 46 name: "xmlWrap can error", 47 err: "hello there", 48 expectError: true, 49 }, 50 { 51 name: "xmlWrap always errors on interrupt", 52 err: "", 53 shouldInterrupt: true, 54 expectError: true, 55 }, 56 { 57 name: "xmlWrap errors on interrupt", 58 shouldInterrupt: true, 59 err: "the step failed", 60 expectError: true, 61 }, 62 { 63 name: "xmlWrap skips errors when already interrupted", 64 interrupted: true, 65 err: "this failed because we interrupted the previous step", 66 expectSkipped: true, 67 }, 68 { 69 name: "xmlWrap can pass when interrupted", 70 interrupted: true, 71 err: "", 72 }, 73 } 74 75 for _, tc := range cases { 76 interrupt := time.NewTimer(time.Duration(0)) 77 terminate := time.NewTimer(time.Duration(0)) 78 c := NewControl(time.Duration(0), interrupt, terminate, false) 79 c.interrupted = tc.interrupted 80 suite.Cases = suite.Cases[:0] 81 suite.Failures = 6 82 suite.Tests = 9 83 err := c.XMLWrap(&suite, tc.name, func() error { 84 if tc.shouldInterrupt { 85 c.interrupted = true 86 } 87 if tc.err != "" { 88 return errors.New(tc.err) 89 } 90 return nil 91 }) 92 93 if tc.shouldInterrupt && tc.expectError { 94 if err == nil { 95 t.Fatalf("Case %s did not error", tc.name) 96 } 97 if tc.err == "" { 98 tc.err = err.Error() 99 } 100 } 101 if (tc.err == "") != (err == nil) { 102 t.Errorf("Case %s expected err: %s != actual: %v", tc.name, tc.err, err) 103 } 104 if tc.shouldInterrupt && !c.interrupted { 105 t.Errorf("Case %s did not interrupt", tc.name) 106 } 107 if len(suite.Cases) != 1 { 108 t.Fatalf("Case %s did not result in a single suite testcase: %v", tc.name, suite.Cases) 109 } 110 111 sc := suite.Cases[0] 112 if sc.Name != tc.name { 113 t.Errorf("Case %s resulted in wrong test case name %s", tc.name, sc.Name) 114 } 115 if tc.expectError { 116 if sc.Failure != tc.err { 117 t.Errorf("Case %s expected error %s but got %s", tc.name, tc.err, sc.Failure) 118 } 119 if suite.Failures != 7 { 120 t.Errorf("Case %s failed and should increase suite failures from 6 to 7, found: %d", tc.name, suite.Failures) 121 } 122 } else if tc.expectSkipped { 123 if sc.Skipped != tc.err { 124 t.Errorf("Case %s expected skipped %s but got %s", tc.name, tc.err, sc.Skipped) 125 } 126 if suite.Failures != 7 { 127 t.Errorf("Case %s interrupted and increase suite failures from 6 to 7, found: %d", tc.name, suite.Failures) 128 } 129 } else { 130 if suite.Failures != 6 { 131 t.Errorf("Case %s passed so suite failures should remain at 6, found: %d", tc.name, suite.Failures) 132 } 133 } 134 135 } 136 } 137 138 func TestOutput(t *testing.T) { 139 cases := []struct { 140 name string 141 terminated bool 142 interrupted bool 143 causeTermination bool 144 causeInterruption bool 145 pass bool 146 sleep int 147 output bool 148 shouldError bool 149 shouldInterrupt bool 150 shouldTerminate bool 151 }{ 152 { 153 name: "finishRunning can pass", 154 pass: true, 155 }, 156 { 157 name: "output can pass", 158 output: true, 159 pass: true, 160 }, 161 { 162 name: "finishRuning can fail", 163 pass: false, 164 shouldError: true, 165 }, 166 { 167 name: "output can fail", 168 pass: false, 169 output: true, 170 shouldError: true, 171 }, 172 { 173 name: "finishRunning should error when terminated", 174 terminated: true, 175 pass: true, 176 shouldError: true, 177 }, 178 { 179 name: "output should error when terminated", 180 terminated: true, 181 pass: true, 182 output: true, 183 shouldError: true, 184 }, 185 { 186 name: "finishRunning should interrupt when interrupted", 187 pass: true, 188 sleep: 60, 189 causeInterruption: true, 190 shouldError: true, 191 }, 192 { 193 name: "output should interrupt when interrupted", 194 pass: true, 195 sleep: 60, 196 output: true, 197 causeInterruption: true, 198 shouldError: true, 199 }, 200 { 201 name: "output should terminate when terminated", 202 pass: true, 203 sleep: 60, 204 output: true, 205 causeTermination: true, 206 shouldError: true, 207 }, 208 { 209 name: "finishRunning should terminate when terminated", 210 pass: true, 211 sleep: 60, 212 causeTermination: true, 213 shouldError: true, 214 }, 215 } 216 217 clearTimers := func(c *Control) { 218 if !c.Terminate.Stop() { 219 <-c.Terminate.C 220 } 221 if !c.Interrupt.Stop() { 222 <-c.Interrupt.C 223 } 224 } 225 226 for _, tc := range cases { 227 log.Println(tc.name) 228 interrupt := time.NewTimer(time.Duration(0)) 229 terminate := time.NewTimer(time.Duration(0)) 230 c := NewControl(time.Duration(0), interrupt, terminate, false) 231 c.terminated = tc.terminated 232 c.interrupted = tc.interrupted 233 clearTimers(c) 234 if tc.causeInterruption { 235 interrupt.Reset(0) 236 } 237 if tc.causeTermination { 238 terminate.Reset(0) 239 } 240 var cmd *exec.Cmd 241 if !tc.pass { 242 cmd = exec.Command("false") 243 } else if tc.sleep == 0 { 244 cmd = exec.Command("true") 245 } else { 246 cmd = exec.Command("sleep", strconv.Itoa(tc.sleep)) 247 } 248 var err error 249 if tc.output { 250 _, err = c.Output(cmd) 251 } else { 252 err = c.FinishRunning(cmd) 253 } 254 if err == nil == tc.shouldError { 255 t.Errorf("Step %s shouldError=%v error: %v", tc.name, tc.shouldError, err) 256 } 257 if tc.causeInterruption && !c.interrupted { 258 t.Errorf("Step %s did not interrupt, err: %v", tc.name, err) 259 } else if tc.causeInterruption && !terminate.Reset(0) { 260 t.Errorf("Step %s did not reset the terminate timer: %v", tc.name, err) 261 } 262 if tc.causeTermination && !c.terminated { 263 t.Errorf("Step %s did not terminate, err: %v", tc.name, err) 264 } 265 } 266 } 267 268 func TestFinishRunningParallel(t *testing.T) { 269 cases := []struct { 270 name string 271 terminated bool 272 interrupted bool 273 causeTermination bool 274 causeInterruption bool 275 cmds []*exec.Cmd 276 shouldError bool 277 shouldInterrupt bool 278 shouldTerminate bool 279 }{ 280 { 281 name: "finishRunningParallel with single command can pass", 282 cmds: []*exec.Cmd{exec.Command("true")}, 283 }, 284 { 285 name: "finishRunningParallel with multiple commands can pass", 286 cmds: []*exec.Cmd{exec.Command("true"), exec.Command("true")}, 287 }, 288 { 289 name: "finishRunningParallel with single command can fail", 290 cmds: []*exec.Cmd{exec.Command("false")}, 291 shouldError: true, 292 }, 293 { 294 name: "finishRunningParallel with multiple commands can fail", 295 cmds: []*exec.Cmd{exec.Command("true"), exec.Command("false")}, 296 shouldError: true, 297 }, 298 { 299 name: "finishRunningParallel should error when terminated", 300 cmds: []*exec.Cmd{exec.Command("true"), exec.Command("true")}, 301 terminated: true, 302 shouldError: true, 303 }, 304 { 305 name: "finishRunningParallel should interrupt when interrupted", 306 cmds: []*exec.Cmd{exec.Command("true"), exec.Command("sleep", "60"), exec.Command("sleep", "30")}, 307 causeInterruption: true, 308 shouldError: true, 309 }, 310 { 311 name: "finishRunningParallel should terminate when terminated", 312 cmds: []*exec.Cmd{exec.Command("true"), exec.Command("sleep", "60"), exec.Command("sleep", "30")}, 313 causeTermination: true, 314 shouldError: true, 315 }, 316 } 317 318 clearTimers := func(c *Control) { 319 if !c.Terminate.Stop() { 320 <-c.Terminate.C 321 } 322 if !c.Interrupt.Stop() { 323 <-c.Interrupt.C 324 } 325 } 326 327 for _, tc := range cases { 328 log.Println(tc.name) 329 interrupt := time.NewTimer(time.Duration(0)) 330 terminate := time.NewTimer(time.Duration(0)) 331 c := NewControl(time.Duration(0), interrupt, terminate, false) 332 c.terminated = tc.terminated 333 c.interrupted = tc.interrupted 334 clearTimers(c) 335 if tc.causeInterruption { 336 interrupt.Reset(1 * time.Second) 337 } 338 if tc.causeTermination { 339 terminate.Reset(1 * time.Second) 340 } 341 342 err := c.FinishRunningParallel(tc.cmds...) 343 if err == nil == tc.shouldError { 344 t.Errorf("TC %q shouldError=%v error: %v", tc.name, tc.shouldError, err) 345 } 346 if tc.causeInterruption && !c.interrupted { 347 t.Errorf("TC %q did not interrupt, err: %v", tc.name, err) 348 } else if tc.causeInterruption && !terminate.Reset(0) { 349 t.Errorf("TC %q did not reset the terminate timer: %v", tc.name, err) 350 } 351 if tc.causeTermination && !c.terminated { 352 t.Errorf("TC %q did not terminate, err: %v", tc.name, err) 353 } 354 } 355 } 356 357 func TestOutputOutputs(t *testing.T) { 358 interrupt := time.NewTimer(time.Duration(1) * time.Second) 359 terminate := time.NewTimer(time.Duration(1) * time.Second) 360 c := NewControl(time.Duration(1)*time.Second, interrupt, terminate, false) 361 362 b, err := c.Output(exec.Command("echo", "hello world")) 363 txt := string(b) 364 if err != nil { 365 t.Fatalf("failed to echo: %v", err) 366 } 367 if !strings.Contains(txt, "hello world") { 368 t.Errorf("output() did not echo hello world: %v", txt) 369 } 370 }