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