github.com/portworx/docker@v1.12.1/pkg/integration/utils_test.go (about) 1 package integration 2 3 import ( 4 "io" 5 "io/ioutil" 6 "os" 7 "os/exec" 8 "path/filepath" 9 "runtime" 10 "strconv" 11 "strings" 12 "testing" 13 "time" 14 ) 15 16 func TestIsKilledFalseWithNonKilledProcess(t *testing.T) { 17 var lsCmd *exec.Cmd 18 if runtime.GOOS != "windows" { 19 lsCmd = exec.Command("ls") 20 } else { 21 lsCmd = exec.Command("cmd", "/c", "dir") 22 } 23 24 err := lsCmd.Run() 25 if IsKilled(err) { 26 t.Fatalf("Expected the ls command to not be killed, was.") 27 } 28 } 29 30 func TestIsKilledTrueWithKilledProcess(t *testing.T) { 31 var longCmd *exec.Cmd 32 if runtime.GOOS != "windows" { 33 longCmd = exec.Command("top") 34 } else { 35 longCmd = exec.Command("powershell", "while ($true) { sleep 1 }") 36 } 37 38 // Start a command 39 err := longCmd.Start() 40 if err != nil { 41 t.Fatal(err) 42 } 43 // Capture the error when *dying* 44 done := make(chan error, 1) 45 go func() { 46 done <- longCmd.Wait() 47 }() 48 // Then kill it 49 longCmd.Process.Kill() 50 // Get the error 51 err = <-done 52 if !IsKilled(err) { 53 t.Fatalf("Expected the command to be killed, was not.") 54 } 55 } 56 57 func TestRunCommandWithOutput(t *testing.T) { 58 var ( 59 echoHelloWorldCmd *exec.Cmd 60 expected string 61 ) 62 if runtime.GOOS != "windows" { 63 echoHelloWorldCmd = exec.Command("echo", "hello", "world") 64 expected = "hello world\n" 65 } else { 66 echoHelloWorldCmd = exec.Command("cmd", "/s", "/c", "echo", "hello", "world") 67 expected = "hello world\r\n" 68 } 69 70 out, exitCode, err := RunCommandWithOutput(echoHelloWorldCmd) 71 if out != expected || exitCode != 0 || err != nil { 72 t.Fatalf("Expected command to output %s, got %s, %v with exitCode %v", expected, out, err, exitCode) 73 } 74 } 75 76 func TestRunCommandWithOutputError(t *testing.T) { 77 var ( 78 p string 79 wrongCmd *exec.Cmd 80 expected string 81 expectedExitCode int 82 ) 83 84 if runtime.GOOS != "windows" { 85 p = "$PATH" 86 wrongCmd = exec.Command("ls", "-z") 87 expected = `ls: invalid option -- 'z' 88 Try 'ls --help' for more information. 89 ` 90 expectedExitCode = 2 91 } else { 92 p = "%PATH%" 93 wrongCmd = exec.Command("cmd", "/s", "/c", "dir", "/Z") 94 expected = "Invalid switch - " + strconv.Quote("Z") + ".\r\n" 95 expectedExitCode = 1 96 } 97 cmd := exec.Command("doesnotexists") 98 out, exitCode, err := RunCommandWithOutput(cmd) 99 expectedError := `exec: "doesnotexists": executable file not found in ` + p 100 if out != "" || exitCode != 127 || err == nil || err.Error() != expectedError { 101 t.Fatalf("Expected command to output %s, got %s, %v with exitCode %v", expectedError, out, err, exitCode) 102 } 103 104 out, exitCode, err = RunCommandWithOutput(wrongCmd) 105 106 if out != expected || exitCode != expectedExitCode || err == nil || !strings.Contains(err.Error(), "exit status "+strconv.Itoa(expectedExitCode)) { 107 t.Fatalf("Expected command to output %s, got out:xxx%sxxx, err:%v with exitCode %v", expected, out, err, exitCode) 108 } 109 } 110 111 func TestRunCommandWithStdoutStderr(t *testing.T) { 112 echoHelloWorldCmd := exec.Command("echo", "hello", "world") 113 stdout, stderr, exitCode, err := RunCommandWithStdoutStderr(echoHelloWorldCmd) 114 expected := "hello world\n" 115 if stdout != expected || stderr != "" || exitCode != 0 || err != nil { 116 t.Fatalf("Expected command to output %s, got stdout:%s, stderr:%s, err:%v with exitCode %v", expected, stdout, stderr, err, exitCode) 117 } 118 } 119 120 func TestRunCommandWithStdoutStderrError(t *testing.T) { 121 p := "$PATH" 122 if runtime.GOOS == "windows" { 123 p = "%PATH%" 124 } 125 cmd := exec.Command("doesnotexists") 126 stdout, stderr, exitCode, err := RunCommandWithStdoutStderr(cmd) 127 expectedError := `exec: "doesnotexists": executable file not found in ` + p 128 if stdout != "" || stderr != "" || exitCode != 127 || err == nil || err.Error() != expectedError { 129 t.Fatalf("Expected command to output out:%s, stderr:%s, got stdout:%s, stderr:%s, err:%v with exitCode %v", "", "", stdout, stderr, err, exitCode) 130 } 131 132 wrongLsCmd := exec.Command("ls", "-z") 133 expected := `ls: invalid option -- 'z' 134 Try 'ls --help' for more information. 135 ` 136 137 stdout, stderr, exitCode, err = RunCommandWithStdoutStderr(wrongLsCmd) 138 if stdout != "" && stderr != expected || exitCode != 2 || err == nil || err.Error() != "exit status 2" { 139 t.Fatalf("Expected command to output out:%s, stderr:%s, got stdout:%s, stderr:%s, err:%v with exitCode %v", "", expectedError, stdout, stderr, err, exitCode) 140 } 141 } 142 143 func TestRunCommandWithOutputForDurationFinished(t *testing.T) { 144 // TODO Windows: Port this test 145 if runtime.GOOS == "windows" { 146 t.Skip("Needs porting to Windows") 147 } 148 149 cmd := exec.Command("ls") 150 out, exitCode, timedOut, err := RunCommandWithOutputForDuration(cmd, 50*time.Millisecond) 151 if out == "" || exitCode != 0 || timedOut || err != nil { 152 t.Fatalf("Expected the command to run for less 50 milliseconds and thus not time out, but did not : out:[%s], exitCode:[%d], timedOut:[%v], err:[%v]", out, exitCode, timedOut, err) 153 } 154 } 155 156 func TestRunCommandWithOutputForDurationKilled(t *testing.T) { 157 // TODO Windows: Port this test 158 if runtime.GOOS == "windows" { 159 t.Skip("Needs porting to Windows") 160 } 161 cmd := exec.Command("sh", "-c", "while true ; do echo 1 ; sleep .1 ; done") 162 out, exitCode, timedOut, err := RunCommandWithOutputForDuration(cmd, 500*time.Millisecond) 163 ones := strings.Split(out, "\n") 164 if len(ones) != 6 || exitCode != 0 || !timedOut || err != nil { 165 t.Fatalf("Expected the command to run for 500 milliseconds (and thus print six lines (five with 1, one empty) and time out, but did not : out:[%s], exitCode:%d, timedOut:%v, err:%v", out, exitCode, timedOut, err) 166 } 167 } 168 169 func TestRunCommandWithOutputForDurationErrors(t *testing.T) { 170 cmd := exec.Command("ls") 171 cmd.Stdout = os.Stdout 172 if _, _, _, err := RunCommandWithOutputForDuration(cmd, 1*time.Millisecond); err == nil || err.Error() != "cmd.Stdout already set" { 173 t.Fatalf("Expected an error as cmd.Stdout was already set, did not (err:%s).", err) 174 } 175 cmd = exec.Command("ls") 176 cmd.Stderr = os.Stderr 177 if _, _, _, err := RunCommandWithOutputForDuration(cmd, 1*time.Millisecond); err == nil || err.Error() != "cmd.Stderr already set" { 178 t.Fatalf("Expected an error as cmd.Stderr was already set, did not (err:%s).", err) 179 } 180 } 181 182 func TestRunCommandWithOutputAndTimeoutFinished(t *testing.T) { 183 // TODO Windows: Port this test 184 if runtime.GOOS == "windows" { 185 t.Skip("Needs porting to Windows") 186 } 187 188 cmd := exec.Command("ls") 189 out, exitCode, err := RunCommandWithOutputAndTimeout(cmd, 50*time.Millisecond) 190 if out == "" || exitCode != 0 || err != nil { 191 t.Fatalf("Expected the command to run for less 50 milliseconds and thus not time out, but did not : out:[%s], exitCode:[%d], err:[%v]", out, exitCode, err) 192 } 193 } 194 195 func TestRunCommandWithOutputAndTimeoutKilled(t *testing.T) { 196 // TODO Windows: Port this test 197 if runtime.GOOS == "windows" { 198 t.Skip("Needs porting to Windows") 199 } 200 201 cmd := exec.Command("sh", "-c", "while true ; do echo 1 ; sleep .1 ; done") 202 out, exitCode, err := RunCommandWithOutputAndTimeout(cmd, 500*time.Millisecond) 203 ones := strings.Split(out, "\n") 204 if len(ones) != 6 || exitCode != 0 || err == nil || err.Error() != "command timed out" { 205 t.Fatalf("Expected the command to run for 500 milliseconds (and thus print six lines (five with 1, one empty) and time out with an error 'command timed out', but did not : out:[%s], exitCode:%d, err:%v", out, exitCode, err) 206 } 207 } 208 209 func TestRunCommandWithOutputAndTimeoutErrors(t *testing.T) { 210 cmd := exec.Command("ls") 211 cmd.Stdout = os.Stdout 212 if _, _, err := RunCommandWithOutputAndTimeout(cmd, 1*time.Millisecond); err == nil || err.Error() != "cmd.Stdout already set" { 213 t.Fatalf("Expected an error as cmd.Stdout was already set, did not (err:%s).", err) 214 } 215 cmd = exec.Command("ls") 216 cmd.Stderr = os.Stderr 217 if _, _, err := RunCommandWithOutputAndTimeout(cmd, 1*time.Millisecond); err == nil || err.Error() != "cmd.Stderr already set" { 218 t.Fatalf("Expected an error as cmd.Stderr was already set, did not (err:%s).", err) 219 } 220 } 221 222 func TestRunCommand(t *testing.T) { 223 // TODO Windows: Port this test 224 if runtime.GOOS == "windows" { 225 t.Skip("Needs porting to Windows") 226 } 227 228 p := "$PATH" 229 if runtime.GOOS == "windows" { 230 p = "%PATH%" 231 } 232 lsCmd := exec.Command("ls") 233 exitCode, err := RunCommand(lsCmd) 234 if exitCode != 0 || err != nil { 235 t.Fatalf("Expected runCommand to run the command successfully, got: exitCode:%d, err:%v", exitCode, err) 236 } 237 238 var expectedError string 239 240 exitCode, err = RunCommand(exec.Command("doesnotexists")) 241 expectedError = `exec: "doesnotexists": executable file not found in ` + p 242 if exitCode != 127 || err == nil || err.Error() != expectedError { 243 t.Fatalf("Expected runCommand to run the command successfully, got: exitCode:%d, err:%v", exitCode, err) 244 } 245 wrongLsCmd := exec.Command("ls", "-z") 246 expected := 2 247 expectedError = `exit status 2` 248 exitCode, err = RunCommand(wrongLsCmd) 249 if exitCode != expected || err == nil || err.Error() != expectedError { 250 t.Fatalf("Expected runCommand to run the command successfully, got: exitCode:%d, err:%v", exitCode, err) 251 } 252 } 253 254 func TestRunCommandPipelineWithOutputWithNotEnoughCmds(t *testing.T) { 255 _, _, err := RunCommandPipelineWithOutput(exec.Command("ls")) 256 expectedError := "pipeline does not have multiple cmds" 257 if err == nil || err.Error() != expectedError { 258 t.Fatalf("Expected an error with %s, got err:%s", expectedError, err) 259 } 260 } 261 262 func TestRunCommandPipelineWithOutputErrors(t *testing.T) { 263 p := "$PATH" 264 if runtime.GOOS == "windows" { 265 p = "%PATH%" 266 } 267 cmd1 := exec.Command("ls") 268 cmd1.Stdout = os.Stdout 269 cmd2 := exec.Command("anything really") 270 _, _, err := RunCommandPipelineWithOutput(cmd1, cmd2) 271 if err == nil || err.Error() != "cannot set stdout pipe for anything really: exec: Stdout already set" { 272 t.Fatalf("Expected an error, got %v", err) 273 } 274 275 cmdWithError := exec.Command("doesnotexists") 276 cmdCat := exec.Command("cat") 277 _, _, err = RunCommandPipelineWithOutput(cmdWithError, cmdCat) 278 if err == nil || err.Error() != `starting doesnotexists failed with error: exec: "doesnotexists": executable file not found in `+p { 279 t.Fatalf("Expected an error, got %v", err) 280 } 281 } 282 283 func TestRunCommandPipelineWithOutput(t *testing.T) { 284 cmds := []*exec.Cmd{ 285 // Print 2 characters 286 exec.Command("echo", "-n", "11"), 287 // Count the number or char from stdin (previous command) 288 exec.Command("wc", "-m"), 289 } 290 out, exitCode, err := RunCommandPipelineWithOutput(cmds...) 291 expectedOutput := "2\n" 292 if out != expectedOutput || exitCode != 0 || err != nil { 293 t.Fatalf("Expected %s for commands %v, got out:%s, exitCode:%d, err:%v", expectedOutput, cmds, out, exitCode, err) 294 } 295 } 296 297 // Simple simple test as it is just a passthrough for json.Unmarshal 298 func TestUnmarshalJSON(t *testing.T) { 299 emptyResult := struct{}{} 300 if err := UnmarshalJSON([]byte(""), &emptyResult); err == nil { 301 t.Fatalf("Expected an error, got nothing") 302 } 303 result := struct{ Name string }{} 304 if err := UnmarshalJSON([]byte(`{"name": "name"}`), &result); err != nil { 305 t.Fatal(err) 306 } 307 if result.Name != "name" { 308 t.Fatalf("Expected result.name to be 'name', was '%s'", result.Name) 309 } 310 } 311 312 func TestConvertSliceOfStringsToMap(t *testing.T) { 313 input := []string{"a", "b"} 314 actual := ConvertSliceOfStringsToMap(input) 315 for _, key := range input { 316 if _, ok := actual[key]; !ok { 317 t.Fatalf("Expected output to contains key %s, did not: %v", key, actual) 318 } 319 } 320 } 321 322 func TestCompareDirectoryEntries(t *testing.T) { 323 tmpFolder, err := ioutil.TempDir("", "integration-cli-utils-compare-directories") 324 if err != nil { 325 t.Fatal(err) 326 } 327 defer os.RemoveAll(tmpFolder) 328 329 file1 := filepath.Join(tmpFolder, "file1") 330 file2 := filepath.Join(tmpFolder, "file2") 331 os.Create(file1) 332 os.Create(file2) 333 334 fi1, err := os.Stat(file1) 335 if err != nil { 336 t.Fatal(err) 337 } 338 fi1bis, err := os.Stat(file1) 339 if err != nil { 340 t.Fatal(err) 341 } 342 fi2, err := os.Stat(file2) 343 if err != nil { 344 t.Fatal(err) 345 } 346 347 cases := []struct { 348 e1 []os.FileInfo 349 e2 []os.FileInfo 350 shouldError bool 351 }{ 352 // Empty directories 353 { 354 []os.FileInfo{}, 355 []os.FileInfo{}, 356 false, 357 }, 358 // Same FileInfos 359 { 360 []os.FileInfo{fi1}, 361 []os.FileInfo{fi1}, 362 false, 363 }, 364 // Different FileInfos but same names 365 { 366 []os.FileInfo{fi1}, 367 []os.FileInfo{fi1bis}, 368 false, 369 }, 370 // Different FileInfos, different names 371 { 372 []os.FileInfo{fi1}, 373 []os.FileInfo{fi2}, 374 true, 375 }, 376 } 377 for _, elt := range cases { 378 err := CompareDirectoryEntries(elt.e1, elt.e2) 379 if elt.shouldError && err == nil { 380 t.Fatalf("Should have return an error, did not with %v and %v", elt.e1, elt.e2) 381 } 382 if !elt.shouldError && err != nil { 383 t.Fatalf("Should have not returned an error, but did : %v with %v and %v", err, elt.e1, elt.e2) 384 } 385 } 386 } 387 388 // FIXME make an "unhappy path" test for ListTar without "panicking" :-) 389 func TestListTar(t *testing.T) { 390 // TODO Windows: Figure out why this fails. Should be portable. 391 if runtime.GOOS == "windows" { 392 t.Skip("Failing on Windows - needs further investigation") 393 } 394 tmpFolder, err := ioutil.TempDir("", "integration-cli-utils-list-tar") 395 if err != nil { 396 t.Fatal(err) 397 } 398 defer os.RemoveAll(tmpFolder) 399 400 // Let's create a Tar file 401 srcFile := filepath.Join(tmpFolder, "src") 402 tarFile := filepath.Join(tmpFolder, "src.tar") 403 os.Create(srcFile) 404 cmd := exec.Command("sh", "-c", "tar cf "+tarFile+" "+srcFile) 405 _, err = cmd.CombinedOutput() 406 if err != nil { 407 t.Fatal(err) 408 } 409 410 reader, err := os.Open(tarFile) 411 if err != nil { 412 t.Fatal(err) 413 } 414 defer reader.Close() 415 416 entries, err := ListTar(reader) 417 if err != nil { 418 t.Fatal(err) 419 } 420 if len(entries) != 1 && entries[0] != "src" { 421 t.Fatalf("Expected a tar file with 1 entry (%s), got %v", srcFile, entries) 422 } 423 } 424 425 func TestRandomTmpDirPath(t *testing.T) { 426 path := RandomTmpDirPath("something", runtime.GOOS) 427 428 prefix := "/tmp/something" 429 if runtime.GOOS == "windows" { 430 prefix = os.Getenv("TEMP") + `\something` 431 } 432 expectedSize := len(prefix) + 11 433 434 if !strings.HasPrefix(path, prefix) { 435 t.Fatalf("Expected generated path to have '%s' as prefix, got %s'", prefix, path) 436 } 437 if len(path) != expectedSize { 438 t.Fatalf("Expected generated path to be %d, got %d", expectedSize, len(path)) 439 } 440 } 441 442 func TestConsumeWithSpeed(t *testing.T) { 443 reader := strings.NewReader("1234567890") 444 chunksize := 2 445 446 bytes1, err := ConsumeWithSpeed(reader, chunksize, 1*time.Second, nil) 447 if err != nil { 448 t.Fatal(err) 449 } 450 451 if bytes1 != 10 { 452 t.Fatalf("Expected to have read 10 bytes, got %d", bytes1) 453 } 454 455 } 456 457 func TestConsumeWithSpeedWithStop(t *testing.T) { 458 reader := strings.NewReader("1234567890") 459 chunksize := 2 460 461 stopIt := make(chan bool) 462 463 go func() { 464 time.Sleep(1 * time.Millisecond) 465 stopIt <- true 466 }() 467 468 bytes1, err := ConsumeWithSpeed(reader, chunksize, 20*time.Millisecond, stopIt) 469 if err != nil { 470 t.Fatal(err) 471 } 472 473 if bytes1 != 2 { 474 t.Fatalf("Expected to have read 2 bytes, got %d", bytes1) 475 } 476 477 } 478 479 func TestParseCgroupPathsEmpty(t *testing.T) { 480 cgroupMap := ParseCgroupPaths("") 481 if len(cgroupMap) != 0 { 482 t.Fatalf("Expected an empty map, got %v", cgroupMap) 483 } 484 cgroupMap = ParseCgroupPaths("\n") 485 if len(cgroupMap) != 0 { 486 t.Fatalf("Expected an empty map, got %v", cgroupMap) 487 } 488 cgroupMap = ParseCgroupPaths("something:else\nagain:here") 489 if len(cgroupMap) != 0 { 490 t.Fatalf("Expected an empty map, got %v", cgroupMap) 491 } 492 } 493 494 func TestParseCgroupPaths(t *testing.T) { 495 cgroupMap := ParseCgroupPaths("2:memory:/a\n1:cpuset:/b") 496 if len(cgroupMap) != 2 { 497 t.Fatalf("Expected a map with 2 entries, got %v", cgroupMap) 498 } 499 if value, ok := cgroupMap["memory"]; !ok || value != "/a" { 500 t.Fatalf("Expected cgroupMap to contains an entry for 'memory' with value '/a', got %v", cgroupMap) 501 } 502 if value, ok := cgroupMap["cpuset"]; !ok || value != "/b" { 503 t.Fatalf("Expected cgroupMap to contains an entry for 'cpuset' with value '/b', got %v", cgroupMap) 504 } 505 } 506 507 func TestChannelBufferTimeout(t *testing.T) { 508 expected := "11" 509 510 buf := &ChannelBuffer{make(chan []byte, 1)} 511 defer buf.Close() 512 513 done := make(chan struct{}, 1) 514 go func() { 515 time.Sleep(100 * time.Millisecond) 516 io.Copy(buf, strings.NewReader(expected)) 517 done <- struct{}{} 518 }() 519 520 // Wait long enough 521 b := make([]byte, 2) 522 _, err := buf.ReadTimeout(b, 50*time.Millisecond) 523 if err == nil && err.Error() != "timeout reading from channel" { 524 t.Fatalf("Expected an error, got %s", err) 525 } 526 <-done 527 } 528 529 func TestChannelBuffer(t *testing.T) { 530 expected := "11" 531 532 buf := &ChannelBuffer{make(chan []byte, 1)} 533 defer buf.Close() 534 535 go func() { 536 time.Sleep(100 * time.Millisecond) 537 io.Copy(buf, strings.NewReader(expected)) 538 }() 539 540 // Wait long enough 541 b := make([]byte, 2) 542 _, err := buf.ReadTimeout(b, 200*time.Millisecond) 543 if err != nil { 544 t.Fatal(err) 545 } 546 547 if string(b) != expected { 548 t.Fatalf("Expected '%s', got '%s'", expected, string(b)) 549 } 550 } 551 552 // FIXME doesn't work 553 // func TestRunAtDifferentDate(t *testing.T) { 554 // var date string 555 556 // // Layout for date. MMDDhhmmYYYY 557 // const timeLayout = "20060102" 558 // expectedDate := "20100201" 559 // theDate, err := time.Parse(timeLayout, expectedDate) 560 // if err != nil { 561 // t.Fatal(err) 562 // } 563 564 // RunAtDifferentDate(theDate, func() { 565 // cmd := exec.Command("date", "+%Y%M%d") 566 // out, err := cmd.Output() 567 // if err != nil { 568 // t.Fatal(err) 569 // } 570 // date = string(out) 571 // }) 572 // }