github.com/dooman87/docker@v1.6.1/integration-cli/docker_cli_build_test.go (about) 1 package main 2 3 import ( 4 "archive/tar" 5 "bufio" 6 "bytes" 7 "encoding/json" 8 "fmt" 9 "io/ioutil" 10 "os" 11 "os/exec" 12 "path/filepath" 13 "reflect" 14 "regexp" 15 "runtime" 16 "strconv" 17 "strings" 18 "sync" 19 "testing" 20 "text/template" 21 "time" 22 23 "github.com/docker/docker/builder/command" 24 "github.com/docker/docker/pkg/archive" 25 ) 26 27 func TestBuildJSONEmptyRun(t *testing.T) { 28 name := "testbuildjsonemptyrun" 29 defer deleteImages(name) 30 31 _, err := buildImage( 32 name, 33 ` 34 FROM busybox 35 RUN [] 36 `, 37 true) 38 39 if err != nil { 40 t.Fatal("error when dealing with a RUN statement with empty JSON array") 41 } 42 43 logDone("build - RUN with an empty array should not panic") 44 } 45 46 func TestBuildEmptyWhitespace(t *testing.T) { 47 name := "testbuildemptywhitespace" 48 defer deleteImages(name) 49 50 _, err := buildImage( 51 name, 52 ` 53 FROM busybox 54 COPY 55 quux \ 56 bar 57 `, 58 true) 59 60 if err == nil { 61 t.Fatal("no error when dealing with a COPY statement with no content on the same line") 62 } 63 64 logDone("build - statements with whitespace and no content should generate a parse error") 65 } 66 67 func TestBuildShCmdJSONEntrypoint(t *testing.T) { 68 name := "testbuildshcmdjsonentrypoint" 69 defer deleteImages(name) 70 71 _, err := buildImage( 72 name, 73 ` 74 FROM busybox 75 ENTRYPOINT ["/bin/echo"] 76 CMD echo test 77 `, 78 true) 79 80 if err != nil { 81 t.Fatal(err) 82 } 83 84 out, _, err := runCommandWithOutput( 85 exec.Command( 86 dockerBinary, 87 "run", 88 "--rm", 89 name)) 90 91 if err != nil { 92 t.Fatal(err) 93 } 94 95 if strings.TrimSpace(out) != "/bin/sh -c echo test" { 96 t.Fatal("CMD did not contain /bin/sh -c") 97 } 98 99 logDone("build - CMD should always contain /bin/sh -c when specified without JSON") 100 } 101 102 func TestBuildEnvironmentReplacementUser(t *testing.T) { 103 name := "testbuildenvironmentreplacement" 104 defer deleteImages(name) 105 106 _, err := buildImage(name, ` 107 FROM scratch 108 ENV user foo 109 USER ${user} 110 `, true) 111 if err != nil { 112 t.Fatal(err) 113 } 114 115 res, err := inspectFieldJSON(name, "Config.User") 116 if err != nil { 117 t.Fatal(err) 118 } 119 120 if res != `"foo"` { 121 t.Fatal("User foo from environment not in Config.User on image") 122 } 123 124 logDone("build - user environment replacement") 125 } 126 127 func TestBuildEnvironmentReplacementVolume(t *testing.T) { 128 name := "testbuildenvironmentreplacement" 129 defer deleteImages(name) 130 131 _, err := buildImage(name, ` 132 FROM scratch 133 ENV volume /quux 134 VOLUME ${volume} 135 `, true) 136 if err != nil { 137 t.Fatal(err) 138 } 139 140 res, err := inspectFieldJSON(name, "Config.Volumes") 141 if err != nil { 142 t.Fatal(err) 143 } 144 145 var volumes map[string]interface{} 146 147 if err := json.Unmarshal([]byte(res), &volumes); err != nil { 148 t.Fatal(err) 149 } 150 151 if _, ok := volumes["/quux"]; !ok { 152 t.Fatal("Volume /quux from environment not in Config.Volumes on image") 153 } 154 155 logDone("build - volume environment replacement") 156 } 157 158 func TestBuildEnvironmentReplacementExpose(t *testing.T) { 159 name := "testbuildenvironmentreplacement" 160 defer deleteImages(name) 161 162 _, err := buildImage(name, ` 163 FROM scratch 164 ENV port 80 165 EXPOSE ${port} 166 `, true) 167 if err != nil { 168 t.Fatal(err) 169 } 170 171 res, err := inspectFieldJSON(name, "Config.ExposedPorts") 172 if err != nil { 173 t.Fatal(err) 174 } 175 176 var exposedPorts map[string]interface{} 177 178 if err := json.Unmarshal([]byte(res), &exposedPorts); err != nil { 179 t.Fatal(err) 180 } 181 182 if _, ok := exposedPorts["80/tcp"]; !ok { 183 t.Fatal("Exposed port 80 from environment not in Config.ExposedPorts on image") 184 } 185 186 logDone("build - expose environment replacement") 187 } 188 189 func TestBuildEnvironmentReplacementWorkdir(t *testing.T) { 190 name := "testbuildenvironmentreplacement" 191 defer deleteImages(name) 192 193 _, err := buildImage(name, ` 194 FROM busybox 195 ENV MYWORKDIR /work 196 RUN mkdir ${MYWORKDIR} 197 WORKDIR ${MYWORKDIR} 198 `, true) 199 200 if err != nil { 201 t.Fatal(err) 202 } 203 204 logDone("build - workdir environment replacement") 205 } 206 207 func TestBuildEnvironmentReplacementAddCopy(t *testing.T) { 208 name := "testbuildenvironmentreplacement" 209 defer deleteImages(name) 210 211 ctx, err := fakeContext(` 212 FROM scratch 213 ENV baz foo 214 ENV quux bar 215 ENV dot . 216 217 ADD ${baz} ${dot} 218 COPY ${quux} ${dot} 219 `, 220 map[string]string{ 221 "foo": "test1", 222 "bar": "test2", 223 }) 224 225 if err != nil { 226 t.Fatal(err) 227 } 228 defer ctx.Close() 229 230 if _, err := buildImageFromContext(name, ctx, true); err != nil { 231 t.Fatal(err) 232 } 233 234 logDone("build - add/copy environment replacement") 235 } 236 237 func TestBuildEnvironmentReplacementEnv(t *testing.T) { 238 name := "testbuildenvironmentreplacement" 239 240 defer deleteImages(name) 241 242 _, err := buildImage(name, 243 ` 244 FROM busybox 245 ENV foo zzz 246 ENV bar ${foo} 247 ENV abc1='$foo' 248 ENV env1=$foo env2=${foo} env3="$foo" env4="${foo}" 249 RUN [ "$abc1" = '$foo' ] && (echo "$abc1" | grep -q foo) 250 ENV abc2="\$foo" 251 RUN [ "$abc2" = '$foo' ] && (echo "$abc2" | grep -q foo) 252 ENV abc3 '$foo' 253 RUN [ "$abc3" = '$foo' ] && (echo "$abc3" | grep -q foo) 254 ENV abc4 "\$foo" 255 RUN [ "$abc4" = '$foo' ] && (echo "$abc4" | grep -q foo) 256 `, true) 257 258 if err != nil { 259 t.Fatal(err) 260 } 261 262 res, err := inspectFieldJSON(name, "Config.Env") 263 if err != nil { 264 t.Fatal(err) 265 } 266 267 envResult := []string{} 268 269 if err = unmarshalJSON([]byte(res), &envResult); err != nil { 270 t.Fatal(err) 271 } 272 273 found := false 274 envCount := 0 275 276 for _, env := range envResult { 277 parts := strings.SplitN(env, "=", 2) 278 if parts[0] == "bar" { 279 found = true 280 if parts[1] != "zzz" { 281 t.Fatalf("Could not find replaced var for env `bar`: got %q instead of `zzz`", parts[1]) 282 } 283 } else if strings.HasPrefix(parts[0], "env") { 284 envCount++ 285 if parts[1] != "zzz" { 286 t.Fatalf("%s should be 'foo' but instead its %q", parts[0], parts[1]) 287 } 288 } 289 } 290 291 if !found { 292 t.Fatal("Never found the `bar` env variable") 293 } 294 295 if envCount != 4 { 296 t.Fatalf("Didn't find all env vars - only saw %d\n%s", envCount, envResult) 297 } 298 299 logDone("build - env environment replacement") 300 } 301 302 func TestBuildHandleEscapes(t *testing.T) { 303 name := "testbuildhandleescapes" 304 305 defer deleteImages(name) 306 307 _, err := buildImage(name, 308 ` 309 FROM scratch 310 ENV FOO bar 311 VOLUME ${FOO} 312 `, true) 313 314 if err != nil { 315 t.Fatal(err) 316 } 317 318 var result map[string]map[string]struct{} 319 320 res, err := inspectFieldJSON(name, "Config.Volumes") 321 if err != nil { 322 t.Fatal(err) 323 } 324 325 if err = unmarshalJSON([]byte(res), &result); err != nil { 326 t.Fatal(err) 327 } 328 329 if _, ok := result["bar"]; !ok { 330 t.Fatal("Could not find volume bar set from env foo in volumes table") 331 } 332 333 deleteImages(name) 334 335 _, err = buildImage(name, 336 ` 337 FROM scratch 338 ENV FOO bar 339 VOLUME \${FOO} 340 `, true) 341 342 if err != nil { 343 t.Fatal(err) 344 } 345 346 res, err = inspectFieldJSON(name, "Config.Volumes") 347 if err != nil { 348 t.Fatal(err) 349 } 350 351 if err = unmarshalJSON([]byte(res), &result); err != nil { 352 t.Fatal(err) 353 } 354 355 if _, ok := result["${FOO}"]; !ok { 356 t.Fatal("Could not find volume ${FOO} set from env foo in volumes table") 357 } 358 359 deleteImages(name) 360 361 // this test in particular provides *7* backslashes and expects 6 to come back. 362 // Like above, the first escape is swallowed and the rest are treated as 363 // literals, this one is just less obvious because of all the character noise. 364 365 _, err = buildImage(name, 366 ` 367 FROM scratch 368 ENV FOO bar 369 VOLUME \\\\\\\${FOO} 370 `, true) 371 372 if err != nil { 373 t.Fatal(err) 374 } 375 376 res, err = inspectFieldJSON(name, "Config.Volumes") 377 if err != nil { 378 t.Fatal(err) 379 } 380 381 if err = unmarshalJSON([]byte(res), &result); err != nil { 382 t.Fatal(err) 383 } 384 385 if _, ok := result[`\\\${FOO}`]; !ok { 386 t.Fatal(`Could not find volume \\\${FOO} set from env foo in volumes table`, result) 387 } 388 389 logDone("build - handle escapes") 390 } 391 392 func TestBuildOnBuildLowercase(t *testing.T) { 393 name := "testbuildonbuildlowercase" 394 name2 := "testbuildonbuildlowercase2" 395 396 defer deleteImages(name, name2) 397 398 _, err := buildImage(name, 399 ` 400 FROM busybox 401 onbuild run echo quux 402 `, true) 403 404 if err != nil { 405 t.Fatal(err) 406 } 407 408 _, out, err := buildImageWithOut(name2, fmt.Sprintf(` 409 FROM %s 410 `, name), true) 411 412 if err != nil { 413 t.Fatal(err) 414 } 415 416 if !strings.Contains(out, "quux") { 417 t.Fatalf("Did not receive the expected echo text, got %s", out) 418 } 419 420 if strings.Contains(out, "ONBUILD ONBUILD") { 421 t.Fatalf("Got an ONBUILD ONBUILD error with no error: got %s", out) 422 } 423 424 logDone("build - handle case-insensitive onbuild statement") 425 } 426 427 func TestBuildEnvEscapes(t *testing.T) { 428 name := "testbuildenvescapes" 429 defer deleteImages(name) 430 defer deleteAllContainers() 431 _, err := buildImage(name, 432 ` 433 FROM busybox 434 ENV TEST foo 435 CMD echo \$ 436 `, 437 true) 438 439 out, _, err := runCommandWithOutput(exec.Command(dockerBinary, "run", "-t", name)) 440 441 if err != nil { 442 t.Fatal(err) 443 } 444 445 if strings.TrimSpace(out) != "$" { 446 t.Fatalf("Env TEST was not overwritten with bar when foo was supplied to dockerfile: was %q", strings.TrimSpace(out)) 447 } 448 449 logDone("build - env should handle \\$ properly") 450 } 451 452 func TestBuildEnvOverwrite(t *testing.T) { 453 name := "testbuildenvoverwrite" 454 defer deleteImages(name) 455 defer deleteAllContainers() 456 457 _, err := buildImage(name, 458 ` 459 FROM busybox 460 ENV TEST foo 461 CMD echo ${TEST} 462 `, 463 true) 464 465 if err != nil { 466 t.Fatal(err) 467 } 468 469 out, _, err := runCommandWithOutput(exec.Command(dockerBinary, "run", "-e", "TEST=bar", "-t", name)) 470 471 if err != nil { 472 t.Fatal(err) 473 } 474 475 if strings.TrimSpace(out) != "bar" { 476 t.Fatalf("Env TEST was not overwritten with bar when foo was supplied to dockerfile: was %q", strings.TrimSpace(out)) 477 } 478 479 logDone("build - env should overwrite builder ENV during run") 480 } 481 482 func TestBuildOnBuildForbiddenMaintainerInSourceImage(t *testing.T) { 483 name := "testbuildonbuildforbiddenmaintainerinsourceimage" 484 defer deleteImages("onbuild") 485 defer deleteImages(name) 486 defer deleteAllContainers() 487 488 createCmd := exec.Command(dockerBinary, "create", "busybox", "true") 489 out, _, _, err := runCommandWithStdoutStderr(createCmd) 490 if err != nil { 491 t.Fatal(out, err) 492 } 493 494 cleanedContainerID := stripTrailingCharacters(out) 495 496 commitCmd := exec.Command(dockerBinary, "commit", "--run", "{\"OnBuild\":[\"MAINTAINER docker.io\"]}", cleanedContainerID, "onbuild") 497 498 if _, err := runCommand(commitCmd); err != nil { 499 t.Fatal(err) 500 } 501 502 _, err = buildImage(name, 503 `FROM onbuild`, 504 true) 505 if err != nil { 506 if !strings.Contains(err.Error(), "maintainer isn't allowed as an ONBUILD trigger") { 507 t.Fatalf("Wrong error %v, must be about MAINTAINER and ONBUILD in source image", err) 508 } 509 } else { 510 t.Fatal("Error must not be nil") 511 } 512 logDone("build - onbuild forbidden maintainer in source image") 513 514 } 515 516 func TestBuildOnBuildForbiddenFromInSourceImage(t *testing.T) { 517 name := "testbuildonbuildforbiddenfrominsourceimage" 518 defer deleteImages("onbuild") 519 defer deleteImages(name) 520 defer deleteAllContainers() 521 522 createCmd := exec.Command(dockerBinary, "create", "busybox", "true") 523 out, _, _, err := runCommandWithStdoutStderr(createCmd) 524 if err != nil { 525 t.Fatal(out, err) 526 } 527 528 cleanedContainerID := stripTrailingCharacters(out) 529 530 commitCmd := exec.Command(dockerBinary, "commit", "--run", "{\"OnBuild\":[\"FROM busybox\"]}", cleanedContainerID, "onbuild") 531 532 if _, err := runCommand(commitCmd); err != nil { 533 t.Fatal(err) 534 } 535 536 _, err = buildImage(name, 537 `FROM onbuild`, 538 true) 539 if err != nil { 540 if !strings.Contains(err.Error(), "from isn't allowed as an ONBUILD trigger") { 541 t.Fatalf("Wrong error %v, must be about FROM and ONBUILD in source image", err) 542 } 543 } else { 544 t.Fatal("Error must not be nil") 545 } 546 logDone("build - onbuild forbidden from in source image") 547 548 } 549 550 func TestBuildOnBuildForbiddenChainedInSourceImage(t *testing.T) { 551 name := "testbuildonbuildforbiddenchainedinsourceimage" 552 defer deleteImages("onbuild") 553 defer deleteImages(name) 554 defer deleteAllContainers() 555 556 createCmd := exec.Command(dockerBinary, "create", "busybox", "true") 557 out, _, _, err := runCommandWithStdoutStderr(createCmd) 558 if err != nil { 559 t.Fatal(out, err) 560 } 561 562 cleanedContainerID := stripTrailingCharacters(out) 563 564 commitCmd := exec.Command(dockerBinary, "commit", "--run", "{\"OnBuild\":[\"ONBUILD RUN ls\"]}", cleanedContainerID, "onbuild") 565 566 if _, err := runCommand(commitCmd); err != nil { 567 t.Fatal(err) 568 } 569 570 _, err = buildImage(name, 571 `FROM onbuild`, 572 true) 573 if err != nil { 574 if !strings.Contains(err.Error(), "Chaining ONBUILD via `ONBUILD ONBUILD` isn't allowed") { 575 t.Fatalf("Wrong error %v, must be about chaining ONBUILD in source image", err) 576 } 577 } else { 578 t.Fatal("Error must not be nil") 579 } 580 logDone("build - onbuild forbidden chained in source image") 581 582 } 583 584 func TestBuildOnBuildCmdEntrypointJSON(t *testing.T) { 585 name1 := "onbuildcmd" 586 name2 := "onbuildgenerated" 587 588 defer deleteImages(name2) 589 defer deleteImages(name1) 590 defer deleteAllContainers() 591 592 _, err := buildImage(name1, ` 593 FROM busybox 594 ONBUILD CMD ["hello world"] 595 ONBUILD ENTRYPOINT ["echo"] 596 ONBUILD RUN ["true"]`, 597 false) 598 599 if err != nil { 600 t.Fatal(err) 601 } 602 603 _, err = buildImage(name2, fmt.Sprintf(`FROM %s`, name1), false) 604 605 if err != nil { 606 t.Fatal(err) 607 } 608 609 out, _, err := runCommandWithOutput(exec.Command(dockerBinary, "run", "-t", name2)) 610 if err != nil { 611 t.Fatal(err) 612 } 613 614 if !regexp.MustCompile(`(?m)^hello world`).MatchString(out) { 615 t.Fatal("did not get echo output from onbuild", out) 616 } 617 618 logDone("build - onbuild with json entrypoint/cmd") 619 } 620 621 func TestBuildOnBuildEntrypointJSON(t *testing.T) { 622 name1 := "onbuildcmd" 623 name2 := "onbuildgenerated" 624 625 defer deleteImages(name2) 626 defer deleteImages(name1) 627 defer deleteAllContainers() 628 629 _, err := buildImage(name1, ` 630 FROM busybox 631 ONBUILD ENTRYPOINT ["echo"]`, 632 false) 633 634 if err != nil { 635 t.Fatal(err) 636 } 637 638 _, err = buildImage(name2, fmt.Sprintf("FROM %s\nCMD [\"hello world\"]\n", name1), false) 639 640 if err != nil { 641 t.Fatal(err) 642 } 643 644 out, _, err := runCommandWithOutput(exec.Command(dockerBinary, "run", "-t", name2)) 645 if err != nil { 646 t.Fatal(err) 647 } 648 649 if !regexp.MustCompile(`(?m)^hello world`).MatchString(out) { 650 t.Fatal("got malformed output from onbuild", out) 651 } 652 653 logDone("build - onbuild with json entrypoint") 654 } 655 656 func TestBuildCacheADD(t *testing.T) { 657 name := "testbuildtwoimageswithadd" 658 defer deleteImages(name) 659 server, err := fakeStorage(map[string]string{ 660 "robots.txt": "hello", 661 "index.html": "world", 662 }) 663 if err != nil { 664 t.Fatal(err) 665 } 666 defer server.Close() 667 668 if _, err := buildImage(name, 669 fmt.Sprintf(`FROM scratch 670 ADD %s/robots.txt /`, server.URL()), 671 true); err != nil { 672 t.Fatal(err) 673 } 674 if err != nil { 675 t.Fatal(err) 676 } 677 deleteImages(name) 678 _, out, err := buildImageWithOut(name, 679 fmt.Sprintf(`FROM scratch 680 ADD %s/index.html /`, server.URL()), 681 true) 682 if err != nil { 683 t.Fatal(err) 684 } 685 if strings.Contains(out, "Using cache") { 686 t.Fatal("2nd build used cache on ADD, it shouldn't") 687 } 688 689 logDone("build - build two images with remote ADD") 690 } 691 692 func TestBuildLastModified(t *testing.T) { 693 name := "testbuildlastmodified" 694 defer deleteImages(name) 695 696 server, err := fakeStorage(map[string]string{ 697 "file": "hello", 698 }) 699 if err != nil { 700 t.Fatal(err) 701 } 702 defer server.Close() 703 704 var out, out2 string 705 706 dFmt := `FROM busybox 707 ADD %s/file / 708 RUN ls -le /file` 709 710 dockerfile := fmt.Sprintf(dFmt, server.URL()) 711 712 if _, out, err = buildImageWithOut(name, dockerfile, false); err != nil { 713 t.Fatal(err) 714 } 715 716 originMTime := regexp.MustCompile(`root.*/file.*\n`).FindString(out) 717 // Make sure our regexp is correct 718 if strings.Index(originMTime, "/file") < 0 { 719 t.Fatalf("Missing ls info on 'file':\n%s", out) 720 } 721 722 // Build it again and make sure the mtime of the file didn't change. 723 // Wait a few seconds to make sure the time changed enough to notice 724 time.Sleep(2 * time.Second) 725 726 if _, out2, err = buildImageWithOut(name, dockerfile, false); err != nil { 727 t.Fatal(err) 728 } 729 730 newMTime := regexp.MustCompile(`root.*/file.*\n`).FindString(out2) 731 if newMTime != originMTime { 732 t.Fatalf("MTime changed:\nOrigin:%s\nNew:%s", originMTime, newMTime) 733 } 734 735 // Now 'touch' the file and make sure the timestamp DID change this time 736 // Create a new fakeStorage instead of just using Add() to help windows 737 server, err = fakeStorage(map[string]string{ 738 "file": "hello", 739 }) 740 if err != nil { 741 t.Fatal(err) 742 } 743 defer server.Close() 744 745 dockerfile = fmt.Sprintf(dFmt, server.URL()) 746 747 if _, out2, err = buildImageWithOut(name, dockerfile, false); err != nil { 748 t.Fatal(err) 749 } 750 751 newMTime = regexp.MustCompile(`root.*/file.*\n`).FindString(out2) 752 if newMTime == originMTime { 753 t.Fatalf("MTime didn't change:\nOrigin:%s\nNew:%s", originMTime, newMTime) 754 } 755 756 logDone("build - use Last-Modified header") 757 } 758 759 func TestBuildSixtySteps(t *testing.T) { 760 name := "foobuildsixtysteps" 761 defer deleteImages(name) 762 ctx, err := fakeContext("FROM scratch\n"+strings.Repeat("ADD foo /\n", 60), 763 map[string]string{ 764 "foo": "test1", 765 }) 766 if err != nil { 767 t.Fatal(err) 768 } 769 defer ctx.Close() 770 771 if _, err := buildImageFromContext(name, ctx, true); err != nil { 772 t.Fatal(err) 773 } 774 logDone("build - build an image with sixty build steps") 775 } 776 777 func TestBuildAddSingleFileToRoot(t *testing.T) { 778 name := "testaddimg" 779 defer deleteImages(name) 780 ctx, err := fakeContext(fmt.Sprintf(`FROM busybox 781 RUN echo 'dockerio:x:1001:1001::/bin:/bin/false' >> /etc/passwd 782 RUN echo 'dockerio:x:1001:' >> /etc/group 783 RUN touch /exists 784 RUN chown dockerio.dockerio /exists 785 ADD test_file / 786 RUN [ $(ls -l /test_file | awk '{print $3":"$4}') = 'root:root' ] 787 RUN [ $(ls -l /test_file | awk '{print $1}') = '%s' ] 788 RUN [ $(ls -l /exists | awk '{print $3":"$4}') = 'dockerio:dockerio' ]`, expectedFileChmod), 789 map[string]string{ 790 "test_file": "test1", 791 }) 792 if err != nil { 793 t.Fatal(err) 794 } 795 defer ctx.Close() 796 797 if _, err := buildImageFromContext(name, ctx, true); err != nil { 798 t.Fatal(err) 799 } 800 logDone("build - add single file to root") 801 } 802 803 // Issue #3960: "ADD src ." hangs 804 func TestBuildAddSingleFileToWorkdir(t *testing.T) { 805 name := "testaddsinglefiletoworkdir" 806 defer deleteImages(name) 807 ctx, err := fakeContext(`FROM busybox 808 ADD test_file .`, 809 map[string]string{ 810 "test_file": "test1", 811 }) 812 if err != nil { 813 t.Fatal(err) 814 } 815 defer ctx.Close() 816 817 done := make(chan struct{}) 818 go func() { 819 if _, err := buildImageFromContext(name, ctx, true); err != nil { 820 t.Fatal(err) 821 } 822 close(done) 823 }() 824 select { 825 case <-time.After(5 * time.Second): 826 t.Fatal("Build with adding to workdir timed out") 827 case <-done: 828 } 829 logDone("build - add single file to workdir") 830 } 831 832 func TestBuildAddSingleFileToExistDir(t *testing.T) { 833 name := "testaddsinglefiletoexistdir" 834 defer deleteImages(name) 835 ctx, err := fakeContext(`FROM busybox 836 RUN echo 'dockerio:x:1001:1001::/bin:/bin/false' >> /etc/passwd 837 RUN echo 'dockerio:x:1001:' >> /etc/group 838 RUN mkdir /exists 839 RUN touch /exists/exists_file 840 RUN chown -R dockerio.dockerio /exists 841 ADD test_file /exists/ 842 RUN [ $(ls -l / | grep exists | awk '{print $3":"$4}') = 'dockerio:dockerio' ] 843 RUN [ $(ls -l /exists/test_file | awk '{print $3":"$4}') = 'root:root' ] 844 RUN [ $(ls -l /exists/exists_file | awk '{print $3":"$4}') = 'dockerio:dockerio' ]`, 845 map[string]string{ 846 "test_file": "test1", 847 }) 848 if err != nil { 849 t.Fatal(err) 850 } 851 defer ctx.Close() 852 853 if _, err := buildImageFromContext(name, ctx, true); err != nil { 854 t.Fatal(err) 855 } 856 logDone("build - add single file to existing dir") 857 } 858 859 func TestBuildCopyAddMultipleFiles(t *testing.T) { 860 server, err := fakeStorage(map[string]string{ 861 "robots.txt": "hello", 862 }) 863 if err != nil { 864 t.Fatal(err) 865 } 866 defer server.Close() 867 868 name := "testcopymultiplefilestofile" 869 defer deleteImages(name) 870 ctx, err := fakeContext(fmt.Sprintf(`FROM busybox 871 RUN echo 'dockerio:x:1001:1001::/bin:/bin/false' >> /etc/passwd 872 RUN echo 'dockerio:x:1001:' >> /etc/group 873 RUN mkdir /exists 874 RUN touch /exists/exists_file 875 RUN chown -R dockerio.dockerio /exists 876 COPY test_file1 test_file2 /exists/ 877 ADD test_file3 test_file4 %s/robots.txt /exists/ 878 RUN [ $(ls -l / | grep exists | awk '{print $3":"$4}') = 'dockerio:dockerio' ] 879 RUN [ $(ls -l /exists/test_file1 | awk '{print $3":"$4}') = 'root:root' ] 880 RUN [ $(ls -l /exists/test_file2 | awk '{print $3":"$4}') = 'root:root' ] 881 882 RUN [ $(ls -l /exists/test_file3 | awk '{print $3":"$4}') = 'root:root' ] 883 RUN [ $(ls -l /exists/test_file4 | awk '{print $3":"$4}') = 'root:root' ] 884 RUN [ $(ls -l /exists/robots.txt | awk '{print $3":"$4}') = 'root:root' ] 885 886 RUN [ $(ls -l /exists/exists_file | awk '{print $3":"$4}') = 'dockerio:dockerio' ] 887 `, server.URL()), 888 map[string]string{ 889 "test_file1": "test1", 890 "test_file2": "test2", 891 "test_file3": "test3", 892 "test_file4": "test4", 893 }) 894 defer ctx.Close() 895 if err != nil { 896 t.Fatal(err) 897 } 898 899 if _, err := buildImageFromContext(name, ctx, true); err != nil { 900 t.Fatal(err) 901 } 902 logDone("build - multiple file copy/add tests") 903 } 904 905 func TestBuildAddMultipleFilesToFile(t *testing.T) { 906 name := "testaddmultiplefilestofile" 907 defer deleteImages(name) 908 ctx, err := fakeContext(`FROM scratch 909 ADD file1.txt file2.txt test 910 `, 911 map[string]string{ 912 "file1.txt": "test1", 913 "file2.txt": "test1", 914 }) 915 defer ctx.Close() 916 if err != nil { 917 t.Fatal(err) 918 } 919 920 expected := "When using ADD with more than one source file, the destination must be a directory and end with a /" 921 if _, err := buildImageFromContext(name, ctx, true); err == nil || !strings.Contains(err.Error(), expected) { 922 t.Fatalf("Wrong error: (should contain %q) got:\n%v", expected, err) 923 } 924 925 logDone("build - multiple add files to file") 926 } 927 928 func TestBuildJSONAddMultipleFilesToFile(t *testing.T) { 929 name := "testjsonaddmultiplefilestofile" 930 defer deleteImages(name) 931 ctx, err := fakeContext(`FROM scratch 932 ADD ["file1.txt", "file2.txt", "test"] 933 `, 934 map[string]string{ 935 "file1.txt": "test1", 936 "file2.txt": "test1", 937 }) 938 defer ctx.Close() 939 if err != nil { 940 t.Fatal(err) 941 } 942 943 expected := "When using ADD with more than one source file, the destination must be a directory and end with a /" 944 if _, err := buildImageFromContext(name, ctx, true); err == nil || !strings.Contains(err.Error(), expected) { 945 t.Fatalf("Wrong error: (should contain %q) got:\n%v", expected, err) 946 } 947 948 logDone("build - multiple add files to file json syntax") 949 } 950 951 func TestBuildAddMultipleFilesToFileWild(t *testing.T) { 952 name := "testaddmultiplefilestofilewild" 953 defer deleteImages(name) 954 ctx, err := fakeContext(`FROM scratch 955 ADD file*.txt test 956 `, 957 map[string]string{ 958 "file1.txt": "test1", 959 "file2.txt": "test1", 960 }) 961 defer ctx.Close() 962 if err != nil { 963 t.Fatal(err) 964 } 965 966 expected := "When using ADD with more than one source file, the destination must be a directory and end with a /" 967 if _, err := buildImageFromContext(name, ctx, true); err == nil || !strings.Contains(err.Error(), expected) { 968 t.Fatalf("Wrong error: (should contain %q) got:\n%v", expected, err) 969 } 970 971 logDone("build - multiple add files to file wild") 972 } 973 974 func TestBuildJSONAddMultipleFilesToFileWild(t *testing.T) { 975 name := "testjsonaddmultiplefilestofilewild" 976 defer deleteImages(name) 977 ctx, err := fakeContext(`FROM scratch 978 ADD ["file*.txt", "test"] 979 `, 980 map[string]string{ 981 "file1.txt": "test1", 982 "file2.txt": "test1", 983 }) 984 defer ctx.Close() 985 if err != nil { 986 t.Fatal(err) 987 } 988 989 expected := "When using ADD with more than one source file, the destination must be a directory and end with a /" 990 if _, err := buildImageFromContext(name, ctx, true); err == nil || !strings.Contains(err.Error(), expected) { 991 t.Fatalf("Wrong error: (should contain %q) got:\n%v", expected, err) 992 } 993 994 logDone("build - multiple add files to file wild json syntax") 995 } 996 997 func TestBuildCopyMultipleFilesToFile(t *testing.T) { 998 name := "testcopymultiplefilestofile" 999 defer deleteImages(name) 1000 ctx, err := fakeContext(`FROM scratch 1001 COPY file1.txt file2.txt test 1002 `, 1003 map[string]string{ 1004 "file1.txt": "test1", 1005 "file2.txt": "test1", 1006 }) 1007 defer ctx.Close() 1008 if err != nil { 1009 t.Fatal(err) 1010 } 1011 1012 expected := "When using COPY with more than one source file, the destination must be a directory and end with a /" 1013 if _, err := buildImageFromContext(name, ctx, true); err == nil || !strings.Contains(err.Error(), expected) { 1014 t.Fatalf("Wrong error: (should contain %q) got:\n%v", expected, err) 1015 } 1016 1017 logDone("build - multiple copy files to file") 1018 } 1019 1020 func TestBuildJSONCopyMultipleFilesToFile(t *testing.T) { 1021 name := "testjsoncopymultiplefilestofile" 1022 defer deleteImages(name) 1023 ctx, err := fakeContext(`FROM scratch 1024 COPY ["file1.txt", "file2.txt", "test"] 1025 `, 1026 map[string]string{ 1027 "file1.txt": "test1", 1028 "file2.txt": "test1", 1029 }) 1030 defer ctx.Close() 1031 if err != nil { 1032 t.Fatal(err) 1033 } 1034 1035 expected := "When using COPY with more than one source file, the destination must be a directory and end with a /" 1036 if _, err := buildImageFromContext(name, ctx, true); err == nil || !strings.Contains(err.Error(), expected) { 1037 t.Fatalf("Wrong error: (should contain %q) got:\n%v", expected, err) 1038 } 1039 1040 logDone("build - multiple copy files to file json syntax") 1041 } 1042 1043 func TestBuildAddFileWithWhitespace(t *testing.T) { 1044 name := "testaddfilewithwhitespace" 1045 defer deleteImages(name) 1046 ctx, err := fakeContext(`FROM busybox 1047 RUN mkdir "/test dir" 1048 RUN mkdir "/test_dir" 1049 ADD [ "test file1", "/test_file1" ] 1050 ADD [ "test_file2", "/test file2" ] 1051 ADD [ "test file3", "/test file3" ] 1052 ADD [ "test dir/test_file4", "/test_dir/test_file4" ] 1053 ADD [ "test_dir/test_file5", "/test dir/test_file5" ] 1054 ADD [ "test dir/test_file6", "/test dir/test_file6" ] 1055 RUN [ $(cat "/test_file1") = 'test1' ] 1056 RUN [ $(cat "/test file2") = 'test2' ] 1057 RUN [ $(cat "/test file3") = 'test3' ] 1058 RUN [ $(cat "/test_dir/test_file4") = 'test4' ] 1059 RUN [ $(cat "/test dir/test_file5") = 'test5' ] 1060 RUN [ $(cat "/test dir/test_file6") = 'test6' ]`, 1061 map[string]string{ 1062 "test file1": "test1", 1063 "test_file2": "test2", 1064 "test file3": "test3", 1065 "test dir/test_file4": "test4", 1066 "test_dir/test_file5": "test5", 1067 "test dir/test_file6": "test6", 1068 }) 1069 defer ctx.Close() 1070 if err != nil { 1071 t.Fatal(err) 1072 } 1073 1074 if _, err := buildImageFromContext(name, ctx, true); err != nil { 1075 t.Fatal(err) 1076 } 1077 logDone("build - add file with whitespace") 1078 } 1079 1080 func TestBuildCopyFileWithWhitespace(t *testing.T) { 1081 name := "testcopyfilewithwhitespace" 1082 defer deleteImages(name) 1083 ctx, err := fakeContext(`FROM busybox 1084 RUN mkdir "/test dir" 1085 RUN mkdir "/test_dir" 1086 COPY [ "test file1", "/test_file1" ] 1087 COPY [ "test_file2", "/test file2" ] 1088 COPY [ "test file3", "/test file3" ] 1089 COPY [ "test dir/test_file4", "/test_dir/test_file4" ] 1090 COPY [ "test_dir/test_file5", "/test dir/test_file5" ] 1091 COPY [ "test dir/test_file6", "/test dir/test_file6" ] 1092 RUN [ $(cat "/test_file1") = 'test1' ] 1093 RUN [ $(cat "/test file2") = 'test2' ] 1094 RUN [ $(cat "/test file3") = 'test3' ] 1095 RUN [ $(cat "/test_dir/test_file4") = 'test4' ] 1096 RUN [ $(cat "/test dir/test_file5") = 'test5' ] 1097 RUN [ $(cat "/test dir/test_file6") = 'test6' ]`, 1098 map[string]string{ 1099 "test file1": "test1", 1100 "test_file2": "test2", 1101 "test file3": "test3", 1102 "test dir/test_file4": "test4", 1103 "test_dir/test_file5": "test5", 1104 "test dir/test_file6": "test6", 1105 }) 1106 defer ctx.Close() 1107 if err != nil { 1108 t.Fatal(err) 1109 } 1110 1111 if _, err := buildImageFromContext(name, ctx, true); err != nil { 1112 t.Fatal(err) 1113 } 1114 logDone("build - copy file with whitespace") 1115 } 1116 1117 func TestBuildAddMultipleFilesToFileWithWhitespace(t *testing.T) { 1118 name := "testaddmultiplefilestofilewithwhitespace" 1119 defer deleteImages(name) 1120 ctx, err := fakeContext(`FROM busybox 1121 ADD [ "test file1", "test file2", "test" ] 1122 `, 1123 map[string]string{ 1124 "test file1": "test1", 1125 "test file2": "test2", 1126 }) 1127 defer ctx.Close() 1128 if err != nil { 1129 t.Fatal(err) 1130 } 1131 1132 expected := "When using ADD with more than one source file, the destination must be a directory and end with a /" 1133 if _, err := buildImageFromContext(name, ctx, true); err == nil || !strings.Contains(err.Error(), expected) { 1134 t.Fatalf("Wrong error: (should contain %q) got:\n%v", expected, err) 1135 } 1136 1137 logDone("build - multiple add files to file with whitespace") 1138 } 1139 1140 func TestBuildCopyMultipleFilesToFileWithWhitespace(t *testing.T) { 1141 name := "testcopymultiplefilestofilewithwhitespace" 1142 defer deleteImages(name) 1143 ctx, err := fakeContext(`FROM busybox 1144 COPY [ "test file1", "test file2", "test" ] 1145 `, 1146 map[string]string{ 1147 "test file1": "test1", 1148 "test file2": "test2", 1149 }) 1150 defer ctx.Close() 1151 if err != nil { 1152 t.Fatal(err) 1153 } 1154 1155 expected := "When using COPY with more than one source file, the destination must be a directory and end with a /" 1156 if _, err := buildImageFromContext(name, ctx, true); err == nil || !strings.Contains(err.Error(), expected) { 1157 t.Fatalf("Wrong error: (should contain %q) got:\n%v", expected, err) 1158 } 1159 1160 logDone("build - multiple copy files to file with whitespace") 1161 } 1162 1163 func TestBuildCopyWildcard(t *testing.T) { 1164 name := "testcopywildcard" 1165 defer deleteImages(name) 1166 server, err := fakeStorage(map[string]string{ 1167 "robots.txt": "hello", 1168 "index.html": "world", 1169 }) 1170 if err != nil { 1171 t.Fatal(err) 1172 } 1173 defer server.Close() 1174 1175 ctx, err := fakeContext(fmt.Sprintf(`FROM busybox 1176 COPY file*.txt /tmp/ 1177 RUN ls /tmp/file1.txt /tmp/file2.txt 1178 RUN mkdir /tmp1 1179 COPY dir* /tmp1/ 1180 RUN ls /tmp1/dirt /tmp1/nested_file /tmp1/nested_dir/nest_nest_file 1181 RUN mkdir /tmp2 1182 ADD dir/*dir %s/robots.txt /tmp2/ 1183 RUN ls /tmp2/nest_nest_file /tmp2/robots.txt 1184 `, server.URL()), 1185 map[string]string{ 1186 "file1.txt": "test1", 1187 "file2.txt": "test2", 1188 "dir/nested_file": "nested file", 1189 "dir/nested_dir/nest_nest_file": "2 times nested", 1190 "dirt": "dirty", 1191 }) 1192 defer ctx.Close() 1193 if err != nil { 1194 t.Fatal(err) 1195 } 1196 1197 id1, err := buildImageFromContext(name, ctx, true) 1198 if err != nil { 1199 t.Fatal(err) 1200 } 1201 1202 // Now make sure we use a cache the 2nd time 1203 id2, err := buildImageFromContext(name, ctx, true) 1204 if err != nil { 1205 t.Fatal(err) 1206 } 1207 1208 if id1 != id2 { 1209 t.Fatal("didn't use the cache") 1210 } 1211 1212 logDone("build - copy wild card") 1213 } 1214 1215 func TestBuildCopyWildcardNoFind(t *testing.T) { 1216 name := "testcopywildcardnofind" 1217 defer deleteImages(name) 1218 ctx, err := fakeContext(`FROM busybox 1219 COPY file*.txt /tmp/ 1220 `, nil) 1221 defer ctx.Close() 1222 if err != nil { 1223 t.Fatal(err) 1224 } 1225 1226 _, err = buildImageFromContext(name, ctx, true) 1227 if err == nil { 1228 t.Fatal("should have failed to find a file") 1229 } 1230 if !strings.Contains(err.Error(), "No source files were specified") { 1231 t.Fatalf("Wrong error %v, must be about no source files", err) 1232 } 1233 1234 logDone("build - copy wild card no find") 1235 } 1236 1237 func TestBuildCopyWildcardCache(t *testing.T) { 1238 name := "testcopywildcardcache" 1239 defer deleteImages(name) 1240 ctx, err := fakeContext(`FROM busybox 1241 COPY file1.txt /tmp/`, 1242 map[string]string{ 1243 "file1.txt": "test1", 1244 }) 1245 defer ctx.Close() 1246 if err != nil { 1247 t.Fatal(err) 1248 } 1249 1250 id1, err := buildImageFromContext(name, ctx, true) 1251 if err != nil { 1252 t.Fatal(err) 1253 } 1254 1255 // Now make sure we use a cache the 2nd time even with wild cards. 1256 // Use the same context so the file is the same and the checksum will match 1257 ctx.Add("Dockerfile", `FROM busybox 1258 COPY file*.txt /tmp/`) 1259 1260 id2, err := buildImageFromContext(name, ctx, true) 1261 if err != nil { 1262 t.Fatal(err) 1263 } 1264 1265 if id1 != id2 { 1266 t.Fatal("didn't use the cache") 1267 } 1268 1269 logDone("build - copy wild card cache") 1270 } 1271 1272 func TestBuildAddSingleFileToNonExistingDir(t *testing.T) { 1273 name := "testaddsinglefiletononexistingdir" 1274 defer deleteImages(name) 1275 ctx, err := fakeContext(`FROM busybox 1276 RUN echo 'dockerio:x:1001:1001::/bin:/bin/false' >> /etc/passwd 1277 RUN echo 'dockerio:x:1001:' >> /etc/group 1278 RUN touch /exists 1279 RUN chown dockerio.dockerio /exists 1280 ADD test_file /test_dir/ 1281 RUN [ $(ls -l / | grep test_dir | awk '{print $3":"$4}') = 'root:root' ] 1282 RUN [ $(ls -l /test_dir/test_file | awk '{print $3":"$4}') = 'root:root' ] 1283 RUN [ $(ls -l /exists | awk '{print $3":"$4}') = 'dockerio:dockerio' ]`, 1284 map[string]string{ 1285 "test_file": "test1", 1286 }) 1287 if err != nil { 1288 t.Fatal(err) 1289 } 1290 defer ctx.Close() 1291 1292 if _, err := buildImageFromContext(name, ctx, true); err != nil { 1293 t.Fatal(err) 1294 } 1295 1296 logDone("build - add single file to non-existing dir") 1297 } 1298 1299 func TestBuildAddDirContentToRoot(t *testing.T) { 1300 name := "testadddircontenttoroot" 1301 defer deleteImages(name) 1302 ctx, err := fakeContext(`FROM busybox 1303 RUN echo 'dockerio:x:1001:1001::/bin:/bin/false' >> /etc/passwd 1304 RUN echo 'dockerio:x:1001:' >> /etc/group 1305 RUN touch /exists 1306 RUN chown dockerio.dockerio exists 1307 ADD test_dir / 1308 RUN [ $(ls -l /test_file | awk '{print $3":"$4}') = 'root:root' ] 1309 RUN [ $(ls -l /exists | awk '{print $3":"$4}') = 'dockerio:dockerio' ]`, 1310 map[string]string{ 1311 "test_dir/test_file": "test1", 1312 }) 1313 if err != nil { 1314 t.Fatal(err) 1315 } 1316 defer ctx.Close() 1317 1318 if _, err := buildImageFromContext(name, ctx, true); err != nil { 1319 t.Fatal(err) 1320 } 1321 logDone("build - add directory contents to root") 1322 } 1323 1324 func TestBuildAddDirContentToExistingDir(t *testing.T) { 1325 name := "testadddircontenttoexistingdir" 1326 defer deleteImages(name) 1327 ctx, err := fakeContext(`FROM busybox 1328 RUN echo 'dockerio:x:1001:1001::/bin:/bin/false' >> /etc/passwd 1329 RUN echo 'dockerio:x:1001:' >> /etc/group 1330 RUN mkdir /exists 1331 RUN touch /exists/exists_file 1332 RUN chown -R dockerio.dockerio /exists 1333 ADD test_dir/ /exists/ 1334 RUN [ $(ls -l / | grep exists | awk '{print $3":"$4}') = 'dockerio:dockerio' ] 1335 RUN [ $(ls -l /exists/exists_file | awk '{print $3":"$4}') = 'dockerio:dockerio' ] 1336 RUN [ $(ls -l /exists/test_file | awk '{print $3":"$4}') = 'root:root' ]`, 1337 map[string]string{ 1338 "test_dir/test_file": "test1", 1339 }) 1340 if err != nil { 1341 t.Fatal(err) 1342 } 1343 defer ctx.Close() 1344 1345 if _, err := buildImageFromContext(name, ctx, true); err != nil { 1346 t.Fatal(err) 1347 } 1348 logDone("build - add directory contents to existing dir") 1349 } 1350 1351 func TestBuildAddWholeDirToRoot(t *testing.T) { 1352 name := "testaddwholedirtoroot" 1353 defer deleteImages(name) 1354 ctx, err := fakeContext(fmt.Sprintf(`FROM busybox 1355 RUN echo 'dockerio:x:1001:1001::/bin:/bin/false' >> /etc/passwd 1356 RUN echo 'dockerio:x:1001:' >> /etc/group 1357 RUN touch /exists 1358 RUN chown dockerio.dockerio exists 1359 ADD test_dir /test_dir 1360 RUN [ $(ls -l / | grep test_dir | awk '{print $3":"$4}') = 'root:root' ] 1361 RUN [ $(ls -l / | grep test_dir | awk '{print $1}') = 'drwxr-xr-x' ] 1362 RUN [ $(ls -l /test_dir/test_file | awk '{print $3":"$4}') = 'root:root' ] 1363 RUN [ $(ls -l /test_dir/test_file | awk '{print $1}') = '%s' ] 1364 RUN [ $(ls -l /exists | awk '{print $3":"$4}') = 'dockerio:dockerio' ]`, expectedFileChmod), 1365 map[string]string{ 1366 "test_dir/test_file": "test1", 1367 }) 1368 if err != nil { 1369 t.Fatal(err) 1370 } 1371 defer ctx.Close() 1372 1373 if _, err := buildImageFromContext(name, ctx, true); err != nil { 1374 t.Fatal(err) 1375 } 1376 logDone("build - add whole directory to root") 1377 } 1378 1379 // Testing #5941 1380 func TestBuildAddEtcToRoot(t *testing.T) { 1381 name := "testaddetctoroot" 1382 defer deleteImages(name) 1383 ctx, err := fakeContext(`FROM scratch 1384 ADD . /`, 1385 map[string]string{ 1386 "etc/test_file": "test1", 1387 }) 1388 if err != nil { 1389 t.Fatal(err) 1390 } 1391 defer ctx.Close() 1392 1393 if _, err := buildImageFromContext(name, ctx, true); err != nil { 1394 t.Fatal(err) 1395 } 1396 logDone("build - add etc directory to root") 1397 } 1398 1399 // Testing #9401 1400 func TestBuildAddPreservesFilesSpecialBits(t *testing.T) { 1401 name := "testaddpreservesfilesspecialbits" 1402 defer deleteImages(name) 1403 ctx, err := fakeContext(`FROM busybox 1404 ADD suidbin /usr/bin/suidbin 1405 RUN chmod 4755 /usr/bin/suidbin 1406 RUN [ $(ls -l /usr/bin/suidbin | awk '{print $1}') = '-rwsr-xr-x' ] 1407 ADD ./data/ / 1408 RUN [ $(ls -l /usr/bin/suidbin | awk '{print $1}') = '-rwsr-xr-x' ]`, 1409 map[string]string{ 1410 "suidbin": "suidbin", 1411 "/data/usr/test_file": "test1", 1412 }) 1413 if err != nil { 1414 t.Fatal(err) 1415 } 1416 defer ctx.Close() 1417 1418 if _, err := buildImageFromContext(name, ctx, true); err != nil { 1419 t.Fatal(err) 1420 } 1421 logDone("build - add preserves files special bits") 1422 } 1423 1424 func TestBuildCopySingleFileToRoot(t *testing.T) { 1425 name := "testcopysinglefiletoroot" 1426 defer deleteImages(name) 1427 ctx, err := fakeContext(fmt.Sprintf(`FROM busybox 1428 RUN echo 'dockerio:x:1001:1001::/bin:/bin/false' >> /etc/passwd 1429 RUN echo 'dockerio:x:1001:' >> /etc/group 1430 RUN touch /exists 1431 RUN chown dockerio.dockerio /exists 1432 COPY test_file / 1433 RUN [ $(ls -l /test_file | awk '{print $3":"$4}') = 'root:root' ] 1434 RUN [ $(ls -l /test_file | awk '{print $1}') = '%s' ] 1435 RUN [ $(ls -l /exists | awk '{print $3":"$4}') = 'dockerio:dockerio' ]`, expectedFileChmod), 1436 map[string]string{ 1437 "test_file": "test1", 1438 }) 1439 if err != nil { 1440 t.Fatal(err) 1441 } 1442 defer ctx.Close() 1443 1444 if _, err := buildImageFromContext(name, ctx, true); err != nil { 1445 t.Fatal(err) 1446 } 1447 logDone("build - copy single file to root") 1448 } 1449 1450 // Issue #3960: "ADD src ." hangs - adapted for COPY 1451 func TestBuildCopySingleFileToWorkdir(t *testing.T) { 1452 name := "testcopysinglefiletoworkdir" 1453 defer deleteImages(name) 1454 ctx, err := fakeContext(`FROM busybox 1455 COPY test_file .`, 1456 map[string]string{ 1457 "test_file": "test1", 1458 }) 1459 if err != nil { 1460 t.Fatal(err) 1461 } 1462 defer ctx.Close() 1463 1464 done := make(chan struct{}) 1465 go func() { 1466 if _, err := buildImageFromContext(name, ctx, true); err != nil { 1467 t.Fatal(err) 1468 } 1469 close(done) 1470 }() 1471 select { 1472 case <-time.After(5 * time.Second): 1473 t.Fatal("Build with adding to workdir timed out") 1474 case <-done: 1475 } 1476 logDone("build - copy single file to workdir") 1477 } 1478 1479 func TestBuildCopySingleFileToExistDir(t *testing.T) { 1480 name := "testcopysinglefiletoexistdir" 1481 defer deleteImages(name) 1482 ctx, err := fakeContext(`FROM busybox 1483 RUN echo 'dockerio:x:1001:1001::/bin:/bin/false' >> /etc/passwd 1484 RUN echo 'dockerio:x:1001:' >> /etc/group 1485 RUN mkdir /exists 1486 RUN touch /exists/exists_file 1487 RUN chown -R dockerio.dockerio /exists 1488 COPY test_file /exists/ 1489 RUN [ $(ls -l / | grep exists | awk '{print $3":"$4}') = 'dockerio:dockerio' ] 1490 RUN [ $(ls -l /exists/test_file | awk '{print $3":"$4}') = 'root:root' ] 1491 RUN [ $(ls -l /exists/exists_file | awk '{print $3":"$4}') = 'dockerio:dockerio' ]`, 1492 map[string]string{ 1493 "test_file": "test1", 1494 }) 1495 if err != nil { 1496 t.Fatal(err) 1497 } 1498 defer ctx.Close() 1499 1500 if _, err := buildImageFromContext(name, ctx, true); err != nil { 1501 t.Fatal(err) 1502 } 1503 logDone("build - copy single file to existing dir") 1504 } 1505 1506 func TestBuildCopySingleFileToNonExistDir(t *testing.T) { 1507 name := "testcopysinglefiletononexistdir" 1508 defer deleteImages(name) 1509 ctx, err := fakeContext(`FROM busybox 1510 RUN echo 'dockerio:x:1001:1001::/bin:/bin/false' >> /etc/passwd 1511 RUN echo 'dockerio:x:1001:' >> /etc/group 1512 RUN touch /exists 1513 RUN chown dockerio.dockerio /exists 1514 COPY test_file /test_dir/ 1515 RUN [ $(ls -l / | grep test_dir | awk '{print $3":"$4}') = 'root:root' ] 1516 RUN [ $(ls -l /test_dir/test_file | awk '{print $3":"$4}') = 'root:root' ] 1517 RUN [ $(ls -l /exists | awk '{print $3":"$4}') = 'dockerio:dockerio' ]`, 1518 map[string]string{ 1519 "test_file": "test1", 1520 }) 1521 if err != nil { 1522 t.Fatal(err) 1523 } 1524 defer ctx.Close() 1525 1526 if _, err := buildImageFromContext(name, ctx, true); err != nil { 1527 t.Fatal(err) 1528 } 1529 logDone("build - copy single file to non-existing dir") 1530 } 1531 1532 func TestBuildCopyDirContentToRoot(t *testing.T) { 1533 name := "testcopydircontenttoroot" 1534 defer deleteImages(name) 1535 ctx, err := fakeContext(`FROM busybox 1536 RUN echo 'dockerio:x:1001:1001::/bin:/bin/false' >> /etc/passwd 1537 RUN echo 'dockerio:x:1001:' >> /etc/group 1538 RUN touch /exists 1539 RUN chown dockerio.dockerio exists 1540 COPY test_dir / 1541 RUN [ $(ls -l /test_file | awk '{print $3":"$4}') = 'root:root' ] 1542 RUN [ $(ls -l /exists | awk '{print $3":"$4}') = 'dockerio:dockerio' ]`, 1543 map[string]string{ 1544 "test_dir/test_file": "test1", 1545 }) 1546 if err != nil { 1547 t.Fatal(err) 1548 } 1549 defer ctx.Close() 1550 1551 if _, err := buildImageFromContext(name, ctx, true); err != nil { 1552 t.Fatal(err) 1553 } 1554 logDone("build - copy directory contents to root") 1555 } 1556 1557 func TestBuildCopyDirContentToExistDir(t *testing.T) { 1558 name := "testcopydircontenttoexistdir" 1559 defer deleteImages(name) 1560 ctx, err := fakeContext(`FROM busybox 1561 RUN echo 'dockerio:x:1001:1001::/bin:/bin/false' >> /etc/passwd 1562 RUN echo 'dockerio:x:1001:' >> /etc/group 1563 RUN mkdir /exists 1564 RUN touch /exists/exists_file 1565 RUN chown -R dockerio.dockerio /exists 1566 COPY test_dir/ /exists/ 1567 RUN [ $(ls -l / | grep exists | awk '{print $3":"$4}') = 'dockerio:dockerio' ] 1568 RUN [ $(ls -l /exists/exists_file | awk '{print $3":"$4}') = 'dockerio:dockerio' ] 1569 RUN [ $(ls -l /exists/test_file | awk '{print $3":"$4}') = 'root:root' ]`, 1570 map[string]string{ 1571 "test_dir/test_file": "test1", 1572 }) 1573 if err != nil { 1574 t.Fatal(err) 1575 } 1576 defer ctx.Close() 1577 1578 if _, err := buildImageFromContext(name, ctx, true); err != nil { 1579 t.Fatal(err) 1580 } 1581 logDone("build - copy directory contents to existing dir") 1582 } 1583 1584 func TestBuildCopyWholeDirToRoot(t *testing.T) { 1585 name := "testcopywholedirtoroot" 1586 defer deleteImages(name) 1587 ctx, err := fakeContext(fmt.Sprintf(`FROM busybox 1588 RUN echo 'dockerio:x:1001:1001::/bin:/bin/false' >> /etc/passwd 1589 RUN echo 'dockerio:x:1001:' >> /etc/group 1590 RUN touch /exists 1591 RUN chown dockerio.dockerio exists 1592 COPY test_dir /test_dir 1593 RUN [ $(ls -l / | grep test_dir | awk '{print $3":"$4}') = 'root:root' ] 1594 RUN [ $(ls -l / | grep test_dir | awk '{print $1}') = 'drwxr-xr-x' ] 1595 RUN [ $(ls -l /test_dir/test_file | awk '{print $3":"$4}') = 'root:root' ] 1596 RUN [ $(ls -l /test_dir/test_file | awk '{print $1}') = '%s' ] 1597 RUN [ $(ls -l /exists | awk '{print $3":"$4}') = 'dockerio:dockerio' ]`, expectedFileChmod), 1598 map[string]string{ 1599 "test_dir/test_file": "test1", 1600 }) 1601 if err != nil { 1602 t.Fatal(err) 1603 } 1604 defer ctx.Close() 1605 1606 if _, err := buildImageFromContext(name, ctx, true); err != nil { 1607 t.Fatal(err) 1608 } 1609 logDone("build - copy whole directory to root") 1610 } 1611 1612 func TestBuildCopyEtcToRoot(t *testing.T) { 1613 name := "testcopyetctoroot" 1614 defer deleteImages(name) 1615 ctx, err := fakeContext(`FROM scratch 1616 COPY . /`, 1617 map[string]string{ 1618 "etc/test_file": "test1", 1619 }) 1620 if err != nil { 1621 t.Fatal(err) 1622 } 1623 defer ctx.Close() 1624 1625 if _, err := buildImageFromContext(name, ctx, true); err != nil { 1626 t.Fatal(err) 1627 } 1628 logDone("build - copy etc directory to root") 1629 } 1630 1631 func TestBuildCopyDisallowRemote(t *testing.T) { 1632 name := "testcopydisallowremote" 1633 defer deleteImages(name) 1634 _, out, err := buildImageWithOut(name, `FROM scratch 1635 COPY https://index.docker.io/robots.txt /`, 1636 true) 1637 if err == nil || !strings.Contains(out, "Source can't be a URL for COPY") { 1638 t.Fatalf("Error should be about disallowed remote source, got err: %s, out: %q", err, out) 1639 } 1640 logDone("build - copy - disallow copy from remote") 1641 } 1642 1643 func TestBuildAddBadLinks(t *testing.T) { 1644 const ( 1645 dockerfile = ` 1646 FROM scratch 1647 ADD links.tar / 1648 ADD foo.txt /symlink/ 1649 ` 1650 targetFile = "foo.txt" 1651 ) 1652 var ( 1653 name = "test-link-absolute" 1654 ) 1655 defer deleteImages(name) 1656 ctx, err := fakeContext(dockerfile, nil) 1657 if err != nil { 1658 t.Fatal(err) 1659 } 1660 defer ctx.Close() 1661 1662 tempDir, err := ioutil.TempDir("", "test-link-absolute-temp-") 1663 if err != nil { 1664 t.Fatalf("failed to create temporary directory: %s", tempDir) 1665 } 1666 defer os.RemoveAll(tempDir) 1667 1668 var symlinkTarget string 1669 if runtime.GOOS == "windows" { 1670 var driveLetter string 1671 if abs, err := filepath.Abs(tempDir); err != nil { 1672 t.Fatal(err) 1673 } else { 1674 driveLetter = abs[:1] 1675 } 1676 tempDirWithoutDrive := tempDir[2:] 1677 symlinkTarget = fmt.Sprintf(`%s:\..\..\..\..\..\..\..\..\..\..\..\..%s`, driveLetter, tempDirWithoutDrive) 1678 } else { 1679 symlinkTarget = fmt.Sprintf("/../../../../../../../../../../../..%s", tempDir) 1680 } 1681 1682 tarPath := filepath.Join(ctx.Dir, "links.tar") 1683 nonExistingFile := filepath.Join(tempDir, targetFile) 1684 fooPath := filepath.Join(ctx.Dir, targetFile) 1685 1686 tarOut, err := os.Create(tarPath) 1687 if err != nil { 1688 t.Fatal(err) 1689 } 1690 1691 tarWriter := tar.NewWriter(tarOut) 1692 1693 header := &tar.Header{ 1694 Name: "symlink", 1695 Typeflag: tar.TypeSymlink, 1696 Linkname: symlinkTarget, 1697 Mode: 0755, 1698 Uid: 0, 1699 Gid: 0, 1700 } 1701 1702 err = tarWriter.WriteHeader(header) 1703 if err != nil { 1704 t.Fatal(err) 1705 } 1706 1707 tarWriter.Close() 1708 tarOut.Close() 1709 1710 foo, err := os.Create(fooPath) 1711 if err != nil { 1712 t.Fatal(err) 1713 } 1714 defer foo.Close() 1715 1716 if _, err := foo.WriteString("test"); err != nil { 1717 t.Fatal(err) 1718 } 1719 1720 if _, err := buildImageFromContext(name, ctx, true); err != nil { 1721 t.Fatal(err) 1722 } 1723 1724 if _, err := os.Stat(nonExistingFile); err == nil || err != nil && !os.IsNotExist(err) { 1725 t.Fatalf("%s shouldn't have been written and it shouldn't exist", nonExistingFile) 1726 } 1727 1728 logDone("build - ADD must add files in container") 1729 } 1730 1731 func TestBuildAddBadLinksVolume(t *testing.T) { 1732 const ( 1733 dockerfileTemplate = ` 1734 FROM busybox 1735 RUN ln -s /../../../../../../../../%s /x 1736 VOLUME /x 1737 ADD foo.txt /x/` 1738 targetFile = "foo.txt" 1739 ) 1740 var ( 1741 name = "test-link-absolute-volume" 1742 dockerfile = "" 1743 ) 1744 defer deleteImages(name) 1745 1746 tempDir, err := ioutil.TempDir("", "test-link-absolute-volume-temp-") 1747 if err != nil { 1748 t.Fatalf("failed to create temporary directory: %s", tempDir) 1749 } 1750 defer os.RemoveAll(tempDir) 1751 1752 dockerfile = fmt.Sprintf(dockerfileTemplate, tempDir) 1753 nonExistingFile := filepath.Join(tempDir, targetFile) 1754 1755 ctx, err := fakeContext(dockerfile, nil) 1756 if err != nil { 1757 t.Fatal(err) 1758 } 1759 defer ctx.Close() 1760 fooPath := filepath.Join(ctx.Dir, targetFile) 1761 1762 foo, err := os.Create(fooPath) 1763 if err != nil { 1764 t.Fatal(err) 1765 } 1766 defer foo.Close() 1767 1768 if _, err := foo.WriteString("test"); err != nil { 1769 t.Fatal(err) 1770 } 1771 1772 if _, err := buildImageFromContext(name, ctx, true); err != nil { 1773 t.Fatal(err) 1774 } 1775 1776 if _, err := os.Stat(nonExistingFile); err == nil || err != nil && !os.IsNotExist(err) { 1777 t.Fatalf("%s shouldn't have been written and it shouldn't exist", nonExistingFile) 1778 } 1779 1780 logDone("build - ADD should add files in volume") 1781 } 1782 1783 // Issue #5270 - ensure we throw a better error than "unexpected EOF" 1784 // when we can't access files in the context. 1785 func TestBuildWithInaccessibleFilesInContext(t *testing.T) { 1786 testRequires(t, UnixCli) // test uses chown/chmod: not available on windows 1787 1788 { 1789 name := "testbuildinaccessiblefiles" 1790 defer deleteImages(name) 1791 ctx, err := fakeContext("FROM scratch\nADD . /foo/", map[string]string{"fileWithoutReadAccess": "foo"}) 1792 if err != nil { 1793 t.Fatal(err) 1794 } 1795 defer ctx.Close() 1796 // This is used to ensure we detect inaccessible files early during build in the cli client 1797 pathToFileWithoutReadAccess := filepath.Join(ctx.Dir, "fileWithoutReadAccess") 1798 1799 if err = os.Chown(pathToFileWithoutReadAccess, 0, 0); err != nil { 1800 t.Fatalf("failed to chown file to root: %s", err) 1801 } 1802 if err = os.Chmod(pathToFileWithoutReadAccess, 0700); err != nil { 1803 t.Fatalf("failed to chmod file to 700: %s", err) 1804 } 1805 buildCmd := exec.Command("su", "unprivilegeduser", "-c", fmt.Sprintf("%s build -t %s .", dockerBinary, name)) 1806 buildCmd.Dir = ctx.Dir 1807 out, _, err := runCommandWithOutput(buildCmd) 1808 if err == nil { 1809 t.Fatalf("build should have failed: %s %s", err, out) 1810 } 1811 1812 // check if we've detected the failure before we started building 1813 if !strings.Contains(out, "no permission to read from ") { 1814 t.Fatalf("output should've contained the string: no permission to read from but contained: %s", out) 1815 } 1816 1817 if !strings.Contains(out, "Error checking context is accessible") { 1818 t.Fatalf("output should've contained the string: Error checking context is accessible") 1819 } 1820 } 1821 { 1822 name := "testbuildinaccessibledirectory" 1823 defer deleteImages(name) 1824 ctx, err := fakeContext("FROM scratch\nADD . /foo/", map[string]string{"directoryWeCantStat/bar": "foo"}) 1825 if err != nil { 1826 t.Fatal(err) 1827 } 1828 defer ctx.Close() 1829 // This is used to ensure we detect inaccessible directories early during build in the cli client 1830 pathToDirectoryWithoutReadAccess := filepath.Join(ctx.Dir, "directoryWeCantStat") 1831 pathToFileInDirectoryWithoutReadAccess := filepath.Join(pathToDirectoryWithoutReadAccess, "bar") 1832 1833 if err = os.Chown(pathToDirectoryWithoutReadAccess, 0, 0); err != nil { 1834 t.Fatalf("failed to chown directory to root: %s", err) 1835 } 1836 if err = os.Chmod(pathToDirectoryWithoutReadAccess, 0444); err != nil { 1837 t.Fatalf("failed to chmod directory to 444: %s", err) 1838 } 1839 if err = os.Chmod(pathToFileInDirectoryWithoutReadAccess, 0700); err != nil { 1840 t.Fatalf("failed to chmod file to 700: %s", err) 1841 } 1842 1843 buildCmd := exec.Command("su", "unprivilegeduser", "-c", fmt.Sprintf("%s build -t %s .", dockerBinary, name)) 1844 buildCmd.Dir = ctx.Dir 1845 out, _, err := runCommandWithOutput(buildCmd) 1846 if err == nil { 1847 t.Fatalf("build should have failed: %s %s", err, out) 1848 } 1849 1850 // check if we've detected the failure before we started building 1851 if !strings.Contains(out, "can't stat") { 1852 t.Fatalf("output should've contained the string: can't access %s", out) 1853 } 1854 1855 if !strings.Contains(out, "Error checking context is accessible") { 1856 t.Fatalf("output should've contained the string: Error checking context is accessible") 1857 } 1858 1859 } 1860 { 1861 name := "testlinksok" 1862 defer deleteImages(name) 1863 ctx, err := fakeContext("FROM scratch\nADD . /foo/", nil) 1864 if err != nil { 1865 t.Fatal(err) 1866 } 1867 defer ctx.Close() 1868 1869 target := "../../../../../../../../../../../../../../../../../../../azA" 1870 if err := os.Symlink(filepath.Join(ctx.Dir, "g"), target); err != nil { 1871 t.Fatal(err) 1872 } 1873 defer os.Remove(target) 1874 // This is used to ensure we don't follow links when checking if everything in the context is accessible 1875 // This test doesn't require that we run commands as an unprivileged user 1876 if _, err := buildImageFromContext(name, ctx, true); err != nil { 1877 t.Fatal(err) 1878 } 1879 } 1880 { 1881 name := "testbuildignoredinaccessible" 1882 defer deleteImages(name) 1883 ctx, err := fakeContext("FROM scratch\nADD . /foo/", 1884 map[string]string{ 1885 "directoryWeCantStat/bar": "foo", 1886 ".dockerignore": "directoryWeCantStat", 1887 }) 1888 if err != nil { 1889 t.Fatal(err) 1890 } 1891 defer ctx.Close() 1892 // This is used to ensure we don't try to add inaccessible files when they are ignored by a .dockerignore pattern 1893 pathToDirectoryWithoutReadAccess := filepath.Join(ctx.Dir, "directoryWeCantStat") 1894 pathToFileInDirectoryWithoutReadAccess := filepath.Join(pathToDirectoryWithoutReadAccess, "bar") 1895 if err = os.Chown(pathToDirectoryWithoutReadAccess, 0, 0); err != nil { 1896 t.Fatalf("failed to chown directory to root: %s", err) 1897 } 1898 if err = os.Chmod(pathToDirectoryWithoutReadAccess, 0444); err != nil { 1899 t.Fatalf("failed to chmod directory to 755: %s", err) 1900 } 1901 if err = os.Chmod(pathToFileInDirectoryWithoutReadAccess, 0700); err != nil { 1902 t.Fatalf("failed to chmod file to 444: %s", err) 1903 } 1904 1905 buildCmd := exec.Command("su", "unprivilegeduser", "-c", fmt.Sprintf("%s build -t %s .", dockerBinary, name)) 1906 buildCmd.Dir = ctx.Dir 1907 if out, _, err := runCommandWithOutput(buildCmd); err != nil { 1908 t.Fatalf("build should have worked: %s %s", err, out) 1909 } 1910 1911 } 1912 logDone("build - ADD from context with inaccessible files must not pass") 1913 logDone("build - ADD from context with accessible links must work") 1914 logDone("build - ADD from context with ignored inaccessible files must work") 1915 } 1916 1917 func TestBuildForceRm(t *testing.T) { 1918 containerCountBefore, err := getContainerCount() 1919 if err != nil { 1920 t.Fatalf("failed to get the container count: %s", err) 1921 } 1922 name := "testbuildforcerm" 1923 defer deleteImages(name) 1924 ctx, err := fakeContext("FROM scratch\nRUN true\nRUN thiswillfail", nil) 1925 if err != nil { 1926 t.Fatal(err) 1927 } 1928 defer ctx.Close() 1929 1930 buildCmd := exec.Command(dockerBinary, "build", "-t", name, "--force-rm", ".") 1931 buildCmd.Dir = ctx.Dir 1932 if out, _, err := runCommandWithOutput(buildCmd); err == nil { 1933 t.Fatalf("failed to build the image: %s, %v", out, err) 1934 } 1935 1936 containerCountAfter, err := getContainerCount() 1937 if err != nil { 1938 t.Fatalf("failed to get the container count: %s", err) 1939 } 1940 1941 if containerCountBefore != containerCountAfter { 1942 t.Fatalf("--force-rm shouldn't have left containers behind") 1943 } 1944 1945 logDone("build - ensure --force-rm doesn't leave containers behind") 1946 } 1947 1948 // Test that an infinite sleep during a build is killed if the client disconnects. 1949 // This test is fairly hairy because there are lots of ways to race. 1950 // Strategy: 1951 // * Monitor the output of docker events starting from before 1952 // * Run a 1-year-long sleep from a docker build. 1953 // * When docker events sees container start, close the "docker build" command 1954 // * Wait for docker events to emit a dying event. 1955 func TestBuildCancelationKillsSleep(t *testing.T) { 1956 // TODO(jfrazelle): Make this work on Windows. 1957 testRequires(t, SameHostDaemon) 1958 1959 name := "testbuildcancelation" 1960 defer deleteImages(name) 1961 defer deleteAllContainers() 1962 1963 // (Note: one year, will never finish) 1964 ctx, err := fakeContext("FROM busybox\nRUN sleep 31536000", nil) 1965 if err != nil { 1966 t.Fatal(err) 1967 } 1968 defer ctx.Close() 1969 1970 var wg sync.WaitGroup 1971 defer wg.Wait() 1972 1973 finish := make(chan struct{}) 1974 defer close(finish) 1975 1976 eventStart := make(chan struct{}) 1977 eventDie := make(chan struct{}) 1978 1979 // Start one second ago, to avoid rounding problems 1980 startEpoch := time.Now().Add(-1 * time.Second) 1981 1982 // Goroutine responsible for watching start/die events from `docker events` 1983 wg.Add(1) 1984 go func() { 1985 defer wg.Done() 1986 1987 // Watch for events since epoch. 1988 eventsCmd := exec.Command(dockerBinary, "events", 1989 "-since", fmt.Sprint(startEpoch.Unix())) 1990 stdout, err := eventsCmd.StdoutPipe() 1991 err = eventsCmd.Start() 1992 if err != nil { 1993 t.Fatalf("failed to start 'docker events': %s", err) 1994 } 1995 1996 go func() { 1997 <-finish 1998 eventsCmd.Process.Kill() 1999 }() 2000 2001 var started, died bool 2002 matchStart := regexp.MustCompile(" \\(from busybox\\:latest\\) start$") 2003 matchDie := regexp.MustCompile(" \\(from busybox\\:latest\\) die$") 2004 2005 // 2006 // Read lines of `docker events` looking for container start and stop. 2007 // 2008 scanner := bufio.NewScanner(stdout) 2009 for scanner.Scan() { 2010 if ok := matchStart.MatchString(scanner.Text()); ok { 2011 if started { 2012 t.Fatal("assertion fail: more than one container started") 2013 } 2014 close(eventStart) 2015 started = true 2016 } 2017 if ok := matchDie.MatchString(scanner.Text()); ok { 2018 if died { 2019 t.Fatal("assertion fail: more than one container died") 2020 } 2021 close(eventDie) 2022 died = true 2023 } 2024 } 2025 2026 err = eventsCmd.Wait() 2027 if err != nil && !IsKilled(err) { 2028 t.Fatalf("docker events had bad exit status: %s", err) 2029 } 2030 }() 2031 2032 buildCmd := exec.Command(dockerBinary, "build", "-t", name, ".") 2033 buildCmd.Dir = ctx.Dir 2034 buildCmd.Stdout = os.Stdout 2035 2036 err = buildCmd.Start() 2037 if err != nil { 2038 t.Fatalf("failed to run build: %s", err) 2039 } 2040 2041 select { 2042 case <-time.After(30 * time.Second): 2043 t.Fatal("failed to observe build container start in timely fashion") 2044 case <-eventStart: 2045 // Proceeds from here when we see the container fly past in the 2046 // output of "docker events". 2047 // Now we know the container is running. 2048 } 2049 2050 // Send a kill to the `docker build` command. 2051 // Causes the underlying build to be cancelled due to socket close. 2052 err = buildCmd.Process.Kill() 2053 if err != nil { 2054 t.Fatalf("error killing build command: %s", err) 2055 } 2056 2057 // Get the exit status of `docker build`, check it exited because killed. 2058 err = buildCmd.Wait() 2059 if err != nil && !IsKilled(err) { 2060 t.Fatalf("wait failed during build run: %T %s", err, err) 2061 } 2062 2063 select { 2064 case <-time.After(30 * time.Second): 2065 // If we don't get here in a timely fashion, it wasn't killed. 2066 t.Fatal("container cancel did not succeed") 2067 case <-eventDie: 2068 // We saw the container shut down in the `docker events` stream, 2069 // as expected. 2070 } 2071 2072 logDone("build - ensure canceled job finishes immediately") 2073 } 2074 2075 func TestBuildRm(t *testing.T) { 2076 name := "testbuildrm" 2077 defer deleteImages(name) 2078 ctx, err := fakeContext("FROM scratch\nADD foo /\nADD foo /", map[string]string{"foo": "bar"}) 2079 if err != nil { 2080 t.Fatal(err) 2081 } 2082 defer ctx.Close() 2083 { 2084 containerCountBefore, err := getContainerCount() 2085 if err != nil { 2086 t.Fatalf("failed to get the container count: %s", err) 2087 } 2088 2089 out, _, err := dockerCmdInDir(t, ctx.Dir, "build", "--rm", "-t", name, ".") 2090 2091 if err != nil { 2092 t.Fatal("failed to build the image", out) 2093 } 2094 2095 containerCountAfter, err := getContainerCount() 2096 if err != nil { 2097 t.Fatalf("failed to get the container count: %s", err) 2098 } 2099 2100 if containerCountBefore != containerCountAfter { 2101 t.Fatalf("-rm shouldn't have left containers behind") 2102 } 2103 deleteImages(name) 2104 } 2105 2106 { 2107 containerCountBefore, err := getContainerCount() 2108 if err != nil { 2109 t.Fatalf("failed to get the container count: %s", err) 2110 } 2111 2112 out, _, err := dockerCmdInDir(t, ctx.Dir, "build", "-t", name, ".") 2113 2114 if err != nil { 2115 t.Fatal("failed to build the image", out) 2116 } 2117 2118 containerCountAfter, err := getContainerCount() 2119 if err != nil { 2120 t.Fatalf("failed to get the container count: %s", err) 2121 } 2122 2123 if containerCountBefore != containerCountAfter { 2124 t.Fatalf("--rm shouldn't have left containers behind") 2125 } 2126 deleteImages(name) 2127 } 2128 2129 { 2130 containerCountBefore, err := getContainerCount() 2131 if err != nil { 2132 t.Fatalf("failed to get the container count: %s", err) 2133 } 2134 2135 out, _, err := dockerCmdInDir(t, ctx.Dir, "build", "--rm=false", "-t", name, ".") 2136 2137 if err != nil { 2138 t.Fatal("failed to build the image", out) 2139 } 2140 2141 containerCountAfter, err := getContainerCount() 2142 if err != nil { 2143 t.Fatalf("failed to get the container count: %s", err) 2144 } 2145 2146 if containerCountBefore == containerCountAfter { 2147 t.Fatalf("--rm=false should have left containers behind") 2148 } 2149 deleteAllContainers() 2150 deleteImages(name) 2151 2152 } 2153 2154 logDone("build - ensure --rm doesn't leave containers behind and that --rm=true is the default") 2155 logDone("build - ensure --rm=false overrides the default") 2156 } 2157 2158 func TestBuildWithVolumes(t *testing.T) { 2159 var ( 2160 result map[string]map[string]struct{} 2161 name = "testbuildvolumes" 2162 emptyMap = make(map[string]struct{}) 2163 expected = map[string]map[string]struct{}{ 2164 "/test1": emptyMap, 2165 "/test2": emptyMap, 2166 "/test3": emptyMap, 2167 "/test4": emptyMap, 2168 "/test5": emptyMap, 2169 "/test6": emptyMap, 2170 "[/test7": emptyMap, 2171 "/test8]": emptyMap, 2172 } 2173 ) 2174 defer deleteImages(name) 2175 _, err := buildImage(name, 2176 `FROM scratch 2177 VOLUME /test1 2178 VOLUME /test2 2179 VOLUME /test3 /test4 2180 VOLUME ["/test5", "/test6"] 2181 VOLUME [/test7 /test8] 2182 `, 2183 true) 2184 if err != nil { 2185 t.Fatal(err) 2186 } 2187 res, err := inspectFieldJSON(name, "Config.Volumes") 2188 if err != nil { 2189 t.Fatal(err) 2190 } 2191 2192 err = unmarshalJSON([]byte(res), &result) 2193 if err != nil { 2194 t.Fatal(err) 2195 } 2196 2197 equal := reflect.DeepEqual(&result, &expected) 2198 2199 if !equal { 2200 t.Fatalf("Volumes %s, expected %s", result, expected) 2201 } 2202 2203 logDone("build - with volumes") 2204 } 2205 2206 func TestBuildMaintainer(t *testing.T) { 2207 name := "testbuildmaintainer" 2208 expected := "dockerio" 2209 defer deleteImages(name) 2210 _, err := buildImage(name, 2211 `FROM scratch 2212 MAINTAINER dockerio`, 2213 true) 2214 if err != nil { 2215 t.Fatal(err) 2216 } 2217 res, err := inspectField(name, "Author") 2218 if err != nil { 2219 t.Fatal(err) 2220 } 2221 if res != expected { 2222 t.Fatalf("Maintainer %s, expected %s", res, expected) 2223 } 2224 logDone("build - maintainer") 2225 } 2226 2227 func TestBuildUser(t *testing.T) { 2228 name := "testbuilduser" 2229 expected := "dockerio" 2230 defer deleteImages(name) 2231 _, err := buildImage(name, 2232 `FROM busybox 2233 RUN echo 'dockerio:x:1001:1001::/bin:/bin/false' >> /etc/passwd 2234 USER dockerio 2235 RUN [ $(whoami) = 'dockerio' ]`, 2236 true) 2237 if err != nil { 2238 t.Fatal(err) 2239 } 2240 res, err := inspectField(name, "Config.User") 2241 if err != nil { 2242 t.Fatal(err) 2243 } 2244 if res != expected { 2245 t.Fatalf("User %s, expected %s", res, expected) 2246 } 2247 logDone("build - user") 2248 } 2249 2250 func TestBuildRelativeWorkdir(t *testing.T) { 2251 name := "testbuildrelativeworkdir" 2252 expected := "/test2/test3" 2253 defer deleteImages(name) 2254 _, err := buildImage(name, 2255 `FROM busybox 2256 RUN [ "$PWD" = '/' ] 2257 WORKDIR test1 2258 RUN [ "$PWD" = '/test1' ] 2259 WORKDIR /test2 2260 RUN [ "$PWD" = '/test2' ] 2261 WORKDIR test3 2262 RUN [ "$PWD" = '/test2/test3' ]`, 2263 true) 2264 if err != nil { 2265 t.Fatal(err) 2266 } 2267 res, err := inspectField(name, "Config.WorkingDir") 2268 if err != nil { 2269 t.Fatal(err) 2270 } 2271 if res != expected { 2272 t.Fatalf("Workdir %s, expected %s", res, expected) 2273 } 2274 logDone("build - relative workdir") 2275 } 2276 2277 func TestBuildWorkdirWithEnvVariables(t *testing.T) { 2278 name := "testbuildworkdirwithenvvariables" 2279 expected := "/test1/test2" 2280 defer deleteImages(name) 2281 _, err := buildImage(name, 2282 `FROM busybox 2283 ENV DIRPATH /test1 2284 ENV SUBDIRNAME test2 2285 WORKDIR $DIRPATH 2286 WORKDIR $SUBDIRNAME/$MISSING_VAR`, 2287 true) 2288 if err != nil { 2289 t.Fatal(err) 2290 } 2291 res, err := inspectField(name, "Config.WorkingDir") 2292 if err != nil { 2293 t.Fatal(err) 2294 } 2295 if res != expected { 2296 t.Fatalf("Workdir %s, expected %s", res, expected) 2297 } 2298 logDone("build - workdir with env variables") 2299 } 2300 2301 func TestBuildRelativeCopy(t *testing.T) { 2302 name := "testbuildrelativecopy" 2303 defer deleteImages(name) 2304 dockerfile := ` 2305 FROM busybox 2306 WORKDIR /test1 2307 WORKDIR test2 2308 RUN [ "$PWD" = '/test1/test2' ] 2309 COPY foo ./ 2310 RUN [ "$(cat /test1/test2/foo)" = 'hello' ] 2311 ADD foo ./bar/baz 2312 RUN [ "$(cat /test1/test2/bar/baz)" = 'hello' ] 2313 COPY foo ./bar/baz2 2314 RUN [ "$(cat /test1/test2/bar/baz2)" = 'hello' ] 2315 WORKDIR .. 2316 COPY foo ./ 2317 RUN [ "$(cat /test1/foo)" = 'hello' ] 2318 COPY foo /test3/ 2319 RUN [ "$(cat /test3/foo)" = 'hello' ] 2320 WORKDIR /test4 2321 COPY . . 2322 RUN [ "$(cat /test4/foo)" = 'hello' ] 2323 WORKDIR /test5/test6 2324 COPY foo ../ 2325 RUN [ "$(cat /test5/foo)" = 'hello' ] 2326 ` 2327 ctx, err := fakeContext(dockerfile, map[string]string{ 2328 "foo": "hello", 2329 }) 2330 defer ctx.Close() 2331 if err != nil { 2332 t.Fatal(err) 2333 } 2334 _, err = buildImageFromContext(name, ctx, false) 2335 if err != nil { 2336 t.Fatal(err) 2337 } 2338 logDone("build - relative copy/add") 2339 } 2340 2341 func TestBuildEnv(t *testing.T) { 2342 name := "testbuildenv" 2343 expected := "[PATH=/test:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin PORT=2375]" 2344 defer deleteImages(name) 2345 _, err := buildImage(name, 2346 `FROM busybox 2347 ENV PATH /test:$PATH 2348 ENV PORT 2375 2349 RUN [ $(env | grep PORT) = 'PORT=2375' ]`, 2350 true) 2351 if err != nil { 2352 t.Fatal(err) 2353 } 2354 res, err := inspectField(name, "Config.Env") 2355 if err != nil { 2356 t.Fatal(err) 2357 } 2358 if res != expected { 2359 t.Fatalf("Env %s, expected %s", res, expected) 2360 } 2361 logDone("build - env") 2362 } 2363 2364 func TestBuildContextCleanup(t *testing.T) { 2365 testRequires(t, SameHostDaemon) 2366 2367 name := "testbuildcontextcleanup" 2368 defer deleteImages(name) 2369 entries, err := ioutil.ReadDir("/var/lib/docker/tmp") 2370 if err != nil { 2371 t.Fatalf("failed to list contents of tmp dir: %s", err) 2372 } 2373 _, err = buildImage(name, 2374 `FROM scratch 2375 ENTRYPOINT ["/bin/echo"]`, 2376 true) 2377 if err != nil { 2378 t.Fatal(err) 2379 } 2380 entriesFinal, err := ioutil.ReadDir("/var/lib/docker/tmp") 2381 if err != nil { 2382 t.Fatalf("failed to list contents of tmp dir: %s", err) 2383 } 2384 if err = compareDirectoryEntries(entries, entriesFinal); err != nil { 2385 t.Fatalf("context should have been deleted, but wasn't") 2386 } 2387 2388 logDone("build - verify context cleanup works properly") 2389 } 2390 2391 func TestBuildContextCleanupFailedBuild(t *testing.T) { 2392 testRequires(t, SameHostDaemon) 2393 2394 name := "testbuildcontextcleanup" 2395 defer deleteImages(name) 2396 defer deleteAllContainers() 2397 entries, err := ioutil.ReadDir("/var/lib/docker/tmp") 2398 if err != nil { 2399 t.Fatalf("failed to list contents of tmp dir: %s", err) 2400 } 2401 _, err = buildImage(name, 2402 `FROM scratch 2403 RUN /non/existing/command`, 2404 true) 2405 if err == nil { 2406 t.Fatalf("expected build to fail, but it didn't") 2407 } 2408 entriesFinal, err := ioutil.ReadDir("/var/lib/docker/tmp") 2409 if err != nil { 2410 t.Fatalf("failed to list contents of tmp dir: %s", err) 2411 } 2412 if err = compareDirectoryEntries(entries, entriesFinal); err != nil { 2413 t.Fatalf("context should have been deleted, but wasn't") 2414 } 2415 2416 logDone("build - verify context cleanup works properly after an unsuccessful build") 2417 } 2418 2419 func TestBuildCmd(t *testing.T) { 2420 name := "testbuildcmd" 2421 expected := "[/bin/echo Hello World]" 2422 defer deleteImages(name) 2423 _, err := buildImage(name, 2424 `FROM scratch 2425 CMD ["/bin/echo", "Hello World"]`, 2426 true) 2427 if err != nil { 2428 t.Fatal(err) 2429 } 2430 res, err := inspectField(name, "Config.Cmd") 2431 if err != nil { 2432 t.Fatal(err) 2433 } 2434 if res != expected { 2435 t.Fatalf("Cmd %s, expected %s", res, expected) 2436 } 2437 logDone("build - cmd") 2438 } 2439 2440 func TestBuildExpose(t *testing.T) { 2441 name := "testbuildexpose" 2442 expected := "map[2375/tcp:map[]]" 2443 defer deleteImages(name) 2444 _, err := buildImage(name, 2445 `FROM scratch 2446 EXPOSE 2375`, 2447 true) 2448 if err != nil { 2449 t.Fatal(err) 2450 } 2451 res, err := inspectField(name, "Config.ExposedPorts") 2452 if err != nil { 2453 t.Fatal(err) 2454 } 2455 if res != expected { 2456 t.Fatalf("Exposed ports %s, expected %s", res, expected) 2457 } 2458 logDone("build - expose") 2459 } 2460 2461 func TestBuildExposeMorePorts(t *testing.T) { 2462 // start building docker file with a large number of ports 2463 portList := make([]string, 50) 2464 line := make([]string, 100) 2465 expectedPorts := make([]int, len(portList)*len(line)) 2466 for i := 0; i < len(portList); i++ { 2467 for j := 0; j < len(line); j++ { 2468 p := i*len(line) + j + 1 2469 line[j] = strconv.Itoa(p) 2470 expectedPorts[p-1] = p 2471 } 2472 if i == len(portList)-1 { 2473 portList[i] = strings.Join(line, " ") 2474 } else { 2475 portList[i] = strings.Join(line, " ") + ` \` 2476 } 2477 } 2478 2479 dockerfile := `FROM scratch 2480 EXPOSE {{range .}} {{.}} 2481 {{end}}` 2482 tmpl := template.Must(template.New("dockerfile").Parse(dockerfile)) 2483 buf := bytes.NewBuffer(nil) 2484 tmpl.Execute(buf, portList) 2485 2486 name := "testbuildexpose" 2487 defer deleteImages(name) 2488 _, err := buildImage(name, buf.String(), true) 2489 if err != nil { 2490 t.Fatal(err) 2491 } 2492 2493 // check if all the ports are saved inside Config.ExposedPorts 2494 res, err := inspectFieldJSON(name, "Config.ExposedPorts") 2495 if err != nil { 2496 t.Fatal(err) 2497 } 2498 var exposedPorts map[string]interface{} 2499 if err := json.Unmarshal([]byte(res), &exposedPorts); err != nil { 2500 t.Fatal(err) 2501 } 2502 2503 for _, p := range expectedPorts { 2504 ep := fmt.Sprintf("%d/tcp", p) 2505 if _, ok := exposedPorts[ep]; !ok { 2506 t.Errorf("Port(%s) is not exposed", ep) 2507 } else { 2508 delete(exposedPorts, ep) 2509 } 2510 } 2511 if len(exposedPorts) != 0 { 2512 t.Errorf("Unexpected extra exposed ports %v", exposedPorts) 2513 } 2514 logDone("build - expose large number of ports") 2515 } 2516 2517 func TestBuildExposeOrder(t *testing.T) { 2518 buildID := func(name, exposed string) string { 2519 _, err := buildImage(name, fmt.Sprintf(`FROM scratch 2520 EXPOSE %s`, exposed), true) 2521 if err != nil { 2522 t.Fatal(err) 2523 } 2524 id, err := inspectField(name, "Id") 2525 if err != nil { 2526 t.Fatal(err) 2527 } 2528 return id 2529 } 2530 2531 id1 := buildID("testbuildexpose1", "80 2375") 2532 id2 := buildID("testbuildexpose2", "2375 80") 2533 defer deleteImages("testbuildexpose1", "testbuildexpose2") 2534 if id1 != id2 { 2535 t.Errorf("EXPOSE should invalidate the cache only when ports actually changed") 2536 } 2537 logDone("build - expose order") 2538 } 2539 2540 func TestBuildExposeUpperCaseProto(t *testing.T) { 2541 name := "testbuildexposeuppercaseproto" 2542 expected := "map[5678/udp:map[]]" 2543 defer deleteImages(name) 2544 _, err := buildImage(name, 2545 `FROM scratch 2546 EXPOSE 5678/UDP`, 2547 true) 2548 if err != nil { 2549 t.Fatal(err) 2550 } 2551 res, err := inspectField(name, "Config.ExposedPorts") 2552 if err != nil { 2553 t.Fatal(err) 2554 } 2555 if res != expected { 2556 t.Fatalf("Exposed ports %s, expected %s", res, expected) 2557 } 2558 logDone("build - expose port with upper case proto") 2559 } 2560 2561 func TestBuildExposeHostPort(t *testing.T) { 2562 // start building docker file with ip:hostPort:containerPort 2563 name := "testbuildexpose" 2564 expected := "map[5678/tcp:map[]]" 2565 defer deleteImages(name) 2566 _, out, err := buildImageWithOut(name, 2567 `FROM scratch 2568 EXPOSE 192.168.1.2:2375:5678`, 2569 true) 2570 if err != nil { 2571 t.Fatal(err) 2572 } 2573 2574 if !strings.Contains(out, "to map host ports to container ports (ip:hostPort:containerPort) is deprecated.") { 2575 t.Fatal("Missing warning message") 2576 } 2577 2578 res, err := inspectField(name, "Config.ExposedPorts") 2579 if err != nil { 2580 t.Fatal(err) 2581 } 2582 if res != expected { 2583 t.Fatalf("Exposed ports %s, expected %s", res, expected) 2584 } 2585 logDone("build - ignore exposing host's port") 2586 } 2587 2588 func TestBuildEmptyEntrypointInheritance(t *testing.T) { 2589 name := "testbuildentrypointinheritance" 2590 name2 := "testbuildentrypointinheritance2" 2591 defer deleteImages(name, name2) 2592 2593 _, err := buildImage(name, 2594 `FROM busybox 2595 ENTRYPOINT ["/bin/echo"]`, 2596 true) 2597 if err != nil { 2598 t.Fatal(err) 2599 } 2600 res, err := inspectField(name, "Config.Entrypoint") 2601 if err != nil { 2602 t.Fatal(err) 2603 } 2604 2605 expected := "[/bin/echo]" 2606 if res != expected { 2607 t.Fatalf("Entrypoint %s, expected %s", res, expected) 2608 } 2609 2610 _, err = buildImage(name2, 2611 fmt.Sprintf(`FROM %s 2612 ENTRYPOINT []`, name), 2613 true) 2614 if err != nil { 2615 t.Fatal(err) 2616 } 2617 res, err = inspectField(name2, "Config.Entrypoint") 2618 if err != nil { 2619 t.Fatal(err) 2620 } 2621 2622 expected = "[]" 2623 2624 if res != expected { 2625 t.Fatalf("Entrypoint %s, expected %s", res, expected) 2626 } 2627 2628 logDone("build - empty entrypoint inheritance") 2629 } 2630 2631 func TestBuildEmptyEntrypoint(t *testing.T) { 2632 name := "testbuildentrypoint" 2633 defer deleteImages(name) 2634 expected := "[]" 2635 2636 _, err := buildImage(name, 2637 `FROM busybox 2638 ENTRYPOINT []`, 2639 true) 2640 if err != nil { 2641 t.Fatal(err) 2642 } 2643 res, err := inspectField(name, "Config.Entrypoint") 2644 if err != nil { 2645 t.Fatal(err) 2646 } 2647 if res != expected { 2648 t.Fatalf("Entrypoint %s, expected %s", res, expected) 2649 } 2650 2651 logDone("build - empty entrypoint") 2652 } 2653 2654 func TestBuildEntrypoint(t *testing.T) { 2655 name := "testbuildentrypoint" 2656 expected := "[/bin/echo]" 2657 defer deleteImages(name) 2658 _, err := buildImage(name, 2659 `FROM scratch 2660 ENTRYPOINT ["/bin/echo"]`, 2661 true) 2662 if err != nil { 2663 t.Fatal(err) 2664 } 2665 res, err := inspectField(name, "Config.Entrypoint") 2666 if err != nil { 2667 t.Fatal(err) 2668 } 2669 if res != expected { 2670 t.Fatalf("Entrypoint %s, expected %s", res, expected) 2671 } 2672 2673 logDone("build - entrypoint") 2674 } 2675 2676 // #6445 ensure ONBUILD triggers aren't committed to grandchildren 2677 func TestBuildOnBuildLimitedInheritence(t *testing.T) { 2678 var ( 2679 out2, out3 string 2680 ) 2681 { 2682 name1 := "testonbuildtrigger1" 2683 dockerfile1 := ` 2684 FROM busybox 2685 RUN echo "GRANDPARENT" 2686 ONBUILD RUN echo "ONBUILD PARENT" 2687 ` 2688 ctx, err := fakeContext(dockerfile1, nil) 2689 if err != nil { 2690 t.Fatal(err) 2691 } 2692 defer ctx.Close() 2693 2694 out1, _, err := dockerCmdInDir(t, ctx.Dir, "build", "-t", name1, ".") 2695 if err != nil { 2696 t.Fatalf("build failed to complete: %s, %v", out1, err) 2697 } 2698 defer deleteImages(name1) 2699 } 2700 { 2701 name2 := "testonbuildtrigger2" 2702 dockerfile2 := ` 2703 FROM testonbuildtrigger1 2704 ` 2705 ctx, err := fakeContext(dockerfile2, nil) 2706 if err != nil { 2707 t.Fatal(err) 2708 } 2709 defer ctx.Close() 2710 2711 out2, _, err = dockerCmdInDir(t, ctx.Dir, "build", "-t", name2, ".") 2712 if err != nil { 2713 t.Fatalf("build failed to complete: %s, %v", out2, err) 2714 } 2715 defer deleteImages(name2) 2716 } 2717 { 2718 name3 := "testonbuildtrigger3" 2719 dockerfile3 := ` 2720 FROM testonbuildtrigger2 2721 ` 2722 ctx, err := fakeContext(dockerfile3, nil) 2723 if err != nil { 2724 t.Fatal(err) 2725 } 2726 defer ctx.Close() 2727 2728 out3, _, err = dockerCmdInDir(t, ctx.Dir, "build", "-t", name3, ".") 2729 if err != nil { 2730 t.Fatalf("build failed to complete: %s, %v", out3, err) 2731 } 2732 2733 defer deleteImages(name3) 2734 } 2735 2736 // ONBUILD should be run in second build. 2737 if !strings.Contains(out2, "ONBUILD PARENT") { 2738 t.Fatalf("ONBUILD instruction did not run in child of ONBUILD parent") 2739 } 2740 2741 // ONBUILD should *not* be run in third build. 2742 if strings.Contains(out3, "ONBUILD PARENT") { 2743 t.Fatalf("ONBUILD instruction ran in grandchild of ONBUILD parent") 2744 } 2745 2746 logDone("build - onbuild") 2747 } 2748 2749 func TestBuildWithCache(t *testing.T) { 2750 name := "testbuildwithcache" 2751 defer deleteImages(name) 2752 id1, err := buildImage(name, 2753 `FROM scratch 2754 MAINTAINER dockerio 2755 EXPOSE 5432 2756 ENTRYPOINT ["/bin/echo"]`, 2757 true) 2758 if err != nil { 2759 t.Fatal(err) 2760 } 2761 id2, err := buildImage(name, 2762 `FROM scratch 2763 MAINTAINER dockerio 2764 EXPOSE 5432 2765 ENTRYPOINT ["/bin/echo"]`, 2766 true) 2767 if err != nil { 2768 t.Fatal(err) 2769 } 2770 if id1 != id2 { 2771 t.Fatal("The cache should have been used but hasn't.") 2772 } 2773 logDone("build - with cache") 2774 } 2775 2776 func TestBuildWithoutCache(t *testing.T) { 2777 name := "testbuildwithoutcache" 2778 name2 := "testbuildwithoutcache2" 2779 defer deleteImages(name, name2) 2780 id1, err := buildImage(name, 2781 `FROM scratch 2782 MAINTAINER dockerio 2783 EXPOSE 5432 2784 ENTRYPOINT ["/bin/echo"]`, 2785 true) 2786 if err != nil { 2787 t.Fatal(err) 2788 } 2789 2790 id2, err := buildImage(name2, 2791 `FROM scratch 2792 MAINTAINER dockerio 2793 EXPOSE 5432 2794 ENTRYPOINT ["/bin/echo"]`, 2795 false) 2796 if err != nil { 2797 t.Fatal(err) 2798 } 2799 if id1 == id2 { 2800 t.Fatal("The cache should have been invalided but hasn't.") 2801 } 2802 logDone("build - without cache") 2803 } 2804 2805 func TestBuildConditionalCache(t *testing.T) { 2806 name := "testbuildconditionalcache" 2807 name2 := "testbuildconditionalcache2" 2808 defer deleteImages(name, name2) 2809 2810 dockerfile := ` 2811 FROM busybox 2812 ADD foo /tmp/` 2813 ctx, err := fakeContext(dockerfile, map[string]string{ 2814 "foo": "hello", 2815 }) 2816 if err != nil { 2817 t.Fatal(err) 2818 } 2819 defer ctx.Close() 2820 2821 id1, err := buildImageFromContext(name, ctx, true) 2822 if err != nil { 2823 t.Fatalf("Error building #1: %s", err) 2824 } 2825 2826 if err := ctx.Add("foo", "bye"); err != nil { 2827 t.Fatalf("Error modifying foo: %s", err) 2828 } 2829 2830 id2, err := buildImageFromContext(name, ctx, false) 2831 if err != nil { 2832 t.Fatalf("Error building #2: %s", err) 2833 } 2834 if id2 == id1 { 2835 t.Fatal("Should not have used the cache") 2836 } 2837 2838 id3, err := buildImageFromContext(name, ctx, true) 2839 if err != nil { 2840 t.Fatalf("Error building #3: %s", err) 2841 } 2842 if id3 != id2 { 2843 t.Fatal("Should have used the cache") 2844 } 2845 2846 logDone("build - conditional cache") 2847 } 2848 2849 func TestBuildADDLocalFileWithCache(t *testing.T) { 2850 name := "testbuildaddlocalfilewithcache" 2851 name2 := "testbuildaddlocalfilewithcache2" 2852 defer deleteImages(name, name2) 2853 dockerfile := ` 2854 FROM busybox 2855 MAINTAINER dockerio 2856 ADD foo /usr/lib/bla/bar 2857 RUN [ "$(cat /usr/lib/bla/bar)" = "hello" ]` 2858 ctx, err := fakeContext(dockerfile, map[string]string{ 2859 "foo": "hello", 2860 }) 2861 defer ctx.Close() 2862 if err != nil { 2863 t.Fatal(err) 2864 } 2865 id1, err := buildImageFromContext(name, ctx, true) 2866 if err != nil { 2867 t.Fatal(err) 2868 } 2869 id2, err := buildImageFromContext(name2, ctx, true) 2870 if err != nil { 2871 t.Fatal(err) 2872 } 2873 if id1 != id2 { 2874 t.Fatal("The cache should have been used but hasn't.") 2875 } 2876 logDone("build - add local file with cache") 2877 } 2878 2879 func TestBuildADDMultipleLocalFileWithCache(t *testing.T) { 2880 name := "testbuildaddmultiplelocalfilewithcache" 2881 name2 := "testbuildaddmultiplelocalfilewithcache2" 2882 defer deleteImages(name, name2) 2883 dockerfile := ` 2884 FROM busybox 2885 MAINTAINER dockerio 2886 ADD foo Dockerfile /usr/lib/bla/ 2887 RUN [ "$(cat /usr/lib/bla/foo)" = "hello" ]` 2888 ctx, err := fakeContext(dockerfile, map[string]string{ 2889 "foo": "hello", 2890 }) 2891 defer ctx.Close() 2892 if err != nil { 2893 t.Fatal(err) 2894 } 2895 id1, err := buildImageFromContext(name, ctx, true) 2896 if err != nil { 2897 t.Fatal(err) 2898 } 2899 id2, err := buildImageFromContext(name2, ctx, true) 2900 if err != nil { 2901 t.Fatal(err) 2902 } 2903 if id1 != id2 { 2904 t.Fatal("The cache should have been used but hasn't.") 2905 } 2906 logDone("build - add multiple local files with cache") 2907 } 2908 2909 func TestBuildADDLocalFileWithoutCache(t *testing.T) { 2910 name := "testbuildaddlocalfilewithoutcache" 2911 name2 := "testbuildaddlocalfilewithoutcache2" 2912 defer deleteImages(name, name2) 2913 dockerfile := ` 2914 FROM busybox 2915 MAINTAINER dockerio 2916 ADD foo /usr/lib/bla/bar 2917 RUN [ "$(cat /usr/lib/bla/bar)" = "hello" ]` 2918 ctx, err := fakeContext(dockerfile, map[string]string{ 2919 "foo": "hello", 2920 }) 2921 defer ctx.Close() 2922 if err != nil { 2923 t.Fatal(err) 2924 } 2925 id1, err := buildImageFromContext(name, ctx, true) 2926 if err != nil { 2927 t.Fatal(err) 2928 } 2929 id2, err := buildImageFromContext(name2, ctx, false) 2930 if err != nil { 2931 t.Fatal(err) 2932 } 2933 if id1 == id2 { 2934 t.Fatal("The cache should have been invalided but hasn't.") 2935 } 2936 logDone("build - add local file without cache") 2937 } 2938 2939 func TestBuildCopyDirButNotFile(t *testing.T) { 2940 name := "testbuildcopydirbutnotfile" 2941 name2 := "testbuildcopydirbutnotfile2" 2942 defer deleteImages(name, name2) 2943 dockerfile := ` 2944 FROM scratch 2945 COPY dir /tmp/` 2946 ctx, err := fakeContext(dockerfile, map[string]string{ 2947 "dir/foo": "hello", 2948 }) 2949 defer ctx.Close() 2950 if err != nil { 2951 t.Fatal(err) 2952 } 2953 id1, err := buildImageFromContext(name, ctx, true) 2954 if err != nil { 2955 t.Fatal(err) 2956 } 2957 // Check that adding file with similar name doesn't mess with cache 2958 if err := ctx.Add("dir_file", "hello2"); err != nil { 2959 t.Fatal(err) 2960 } 2961 id2, err := buildImageFromContext(name2, ctx, true) 2962 if err != nil { 2963 t.Fatal(err) 2964 } 2965 if id1 != id2 { 2966 t.Fatal("The cache should have been used but wasn't") 2967 } 2968 logDone("build - add current directory but not file") 2969 } 2970 2971 func TestBuildADDCurrentDirWithCache(t *testing.T) { 2972 name := "testbuildaddcurrentdirwithcache" 2973 name2 := name + "2" 2974 name3 := name + "3" 2975 name4 := name + "4" 2976 name5 := name + "5" 2977 defer deleteImages(name, name2, name3, name4, name5) 2978 dockerfile := ` 2979 FROM scratch 2980 MAINTAINER dockerio 2981 ADD . /usr/lib/bla` 2982 ctx, err := fakeContext(dockerfile, map[string]string{ 2983 "foo": "hello", 2984 }) 2985 defer ctx.Close() 2986 if err != nil { 2987 t.Fatal(err) 2988 } 2989 id1, err := buildImageFromContext(name, ctx, true) 2990 if err != nil { 2991 t.Fatal(err) 2992 } 2993 // Check that adding file invalidate cache of "ADD ." 2994 if err := ctx.Add("bar", "hello2"); err != nil { 2995 t.Fatal(err) 2996 } 2997 id2, err := buildImageFromContext(name2, ctx, true) 2998 if err != nil { 2999 t.Fatal(err) 3000 } 3001 if id1 == id2 { 3002 t.Fatal("The cache should have been invalided but hasn't.") 3003 } 3004 // Check that changing file invalidate cache of "ADD ." 3005 if err := ctx.Add("foo", "hello1"); err != nil { 3006 t.Fatal(err) 3007 } 3008 id3, err := buildImageFromContext(name3, ctx, true) 3009 if err != nil { 3010 t.Fatal(err) 3011 } 3012 if id2 == id3 { 3013 t.Fatal("The cache should have been invalided but hasn't.") 3014 } 3015 // Check that changing file to same content invalidate cache of "ADD ." 3016 time.Sleep(1 * time.Second) // wait second because of mtime precision 3017 if err := ctx.Add("foo", "hello1"); err != nil { 3018 t.Fatal(err) 3019 } 3020 id4, err := buildImageFromContext(name4, ctx, true) 3021 if err != nil { 3022 t.Fatal(err) 3023 } 3024 if id3 == id4 { 3025 t.Fatal("The cache should have been invalided but hasn't.") 3026 } 3027 id5, err := buildImageFromContext(name5, ctx, true) 3028 if err != nil { 3029 t.Fatal(err) 3030 } 3031 if id4 != id5 { 3032 t.Fatal("The cache should have been used but hasn't.") 3033 } 3034 logDone("build - add current directory with cache") 3035 } 3036 3037 func TestBuildADDCurrentDirWithoutCache(t *testing.T) { 3038 name := "testbuildaddcurrentdirwithoutcache" 3039 name2 := "testbuildaddcurrentdirwithoutcache2" 3040 defer deleteImages(name, name2) 3041 dockerfile := ` 3042 FROM scratch 3043 MAINTAINER dockerio 3044 ADD . /usr/lib/bla` 3045 ctx, err := fakeContext(dockerfile, map[string]string{ 3046 "foo": "hello", 3047 }) 3048 defer ctx.Close() 3049 if err != nil { 3050 t.Fatal(err) 3051 } 3052 id1, err := buildImageFromContext(name, ctx, true) 3053 if err != nil { 3054 t.Fatal(err) 3055 } 3056 id2, err := buildImageFromContext(name2, ctx, false) 3057 if err != nil { 3058 t.Fatal(err) 3059 } 3060 if id1 == id2 { 3061 t.Fatal("The cache should have been invalided but hasn't.") 3062 } 3063 logDone("build - add current directory without cache") 3064 } 3065 3066 func TestBuildADDRemoteFileWithCache(t *testing.T) { 3067 name := "testbuildaddremotefilewithcache" 3068 defer deleteImages(name) 3069 server, err := fakeStorage(map[string]string{ 3070 "baz": "hello", 3071 }) 3072 if err != nil { 3073 t.Fatal(err) 3074 } 3075 defer server.Close() 3076 3077 id1, err := buildImage(name, 3078 fmt.Sprintf(`FROM scratch 3079 MAINTAINER dockerio 3080 ADD %s/baz /usr/lib/baz/quux`, server.URL()), 3081 true) 3082 if err != nil { 3083 t.Fatal(err) 3084 } 3085 id2, err := buildImage(name, 3086 fmt.Sprintf(`FROM scratch 3087 MAINTAINER dockerio 3088 ADD %s/baz /usr/lib/baz/quux`, server.URL()), 3089 true) 3090 if err != nil { 3091 t.Fatal(err) 3092 } 3093 if id1 != id2 { 3094 t.Fatal("The cache should have been used but hasn't.") 3095 } 3096 logDone("build - add remote file with cache") 3097 } 3098 3099 func TestBuildADDRemoteFileWithoutCache(t *testing.T) { 3100 name := "testbuildaddremotefilewithoutcache" 3101 name2 := "testbuildaddremotefilewithoutcache2" 3102 defer deleteImages(name, name2) 3103 server, err := fakeStorage(map[string]string{ 3104 "baz": "hello", 3105 }) 3106 if err != nil { 3107 t.Fatal(err) 3108 } 3109 defer server.Close() 3110 3111 id1, err := buildImage(name, 3112 fmt.Sprintf(`FROM scratch 3113 MAINTAINER dockerio 3114 ADD %s/baz /usr/lib/baz/quux`, server.URL()), 3115 true) 3116 if err != nil { 3117 t.Fatal(err) 3118 } 3119 id2, err := buildImage(name2, 3120 fmt.Sprintf(`FROM scratch 3121 MAINTAINER dockerio 3122 ADD %s/baz /usr/lib/baz/quux`, server.URL()), 3123 false) 3124 if err != nil { 3125 t.Fatal(err) 3126 } 3127 if id1 == id2 { 3128 t.Fatal("The cache should have been invalided but hasn't.") 3129 } 3130 logDone("build - add remote file without cache") 3131 } 3132 3133 func TestBuildADDRemoteFileMTime(t *testing.T) { 3134 name := "testbuildaddremotefilemtime" 3135 name2 := name + "2" 3136 name3 := name + "3" 3137 name4 := name + "4" 3138 3139 defer deleteImages(name, name2, name3, name4) 3140 3141 files := map[string]string{"baz": "hello"} 3142 server, err := fakeStorage(files) 3143 if err != nil { 3144 t.Fatal(err) 3145 } 3146 defer server.Close() 3147 3148 ctx, err := fakeContext(fmt.Sprintf(`FROM scratch 3149 MAINTAINER dockerio 3150 ADD %s/baz /usr/lib/baz/quux`, server.URL()), nil) 3151 if err != nil { 3152 t.Fatal(err) 3153 } 3154 defer ctx.Close() 3155 3156 id1, err := buildImageFromContext(name, ctx, true) 3157 if err != nil { 3158 t.Fatal(err) 3159 } 3160 3161 id2, err := buildImageFromContext(name2, ctx, true) 3162 if err != nil { 3163 t.Fatal(err) 3164 } 3165 if id1 != id2 { 3166 t.Fatal("The cache should have been used but wasn't - #1") 3167 } 3168 3169 // Now create a different server withsame contents (causes different mtim) 3170 // This time the cache should not be used 3171 3172 // allow some time for clock to pass as mtime precision is only 1s 3173 time.Sleep(2 * time.Second) 3174 3175 server2, err := fakeStorage(files) 3176 if err != nil { 3177 t.Fatal(err) 3178 } 3179 defer server2.Close() 3180 3181 ctx2, err := fakeContext(fmt.Sprintf(`FROM scratch 3182 MAINTAINER dockerio 3183 ADD %s/baz /usr/lib/baz/quux`, server2.URL()), nil) 3184 if err != nil { 3185 t.Fatal(err) 3186 } 3187 defer ctx2.Close() 3188 id3, err := buildImageFromContext(name3, ctx2, true) 3189 if err != nil { 3190 t.Fatal(err) 3191 } 3192 if id1 == id3 { 3193 t.Fatal("The cache should not have been used but was") 3194 } 3195 3196 // And for good measure do it again and make sure cache is used this time 3197 id4, err := buildImageFromContext(name4, ctx2, true) 3198 if err != nil { 3199 t.Fatal(err) 3200 } 3201 if id3 != id4 { 3202 t.Fatal("The cache should have been used but wasn't - #2") 3203 } 3204 logDone("build - add remote file testing mtime") 3205 } 3206 3207 func TestBuildADDLocalAndRemoteFilesWithCache(t *testing.T) { 3208 name := "testbuildaddlocalandremotefilewithcache" 3209 defer deleteImages(name) 3210 server, err := fakeStorage(map[string]string{ 3211 "baz": "hello", 3212 }) 3213 if err != nil { 3214 t.Fatal(err) 3215 } 3216 defer server.Close() 3217 3218 ctx, err := fakeContext(fmt.Sprintf(`FROM scratch 3219 MAINTAINER dockerio 3220 ADD foo /usr/lib/bla/bar 3221 ADD %s/baz /usr/lib/baz/quux`, server.URL()), 3222 map[string]string{ 3223 "foo": "hello world", 3224 }) 3225 if err != nil { 3226 t.Fatal(err) 3227 } 3228 defer ctx.Close() 3229 id1, err := buildImageFromContext(name, ctx, true) 3230 if err != nil { 3231 t.Fatal(err) 3232 } 3233 id2, err := buildImageFromContext(name, ctx, true) 3234 if err != nil { 3235 t.Fatal(err) 3236 } 3237 if id1 != id2 { 3238 t.Fatal("The cache should have been used but hasn't.") 3239 } 3240 logDone("build - add local and remote file with cache") 3241 } 3242 3243 func testContextTar(t *testing.T, compression archive.Compression) { 3244 ctx, err := fakeContext( 3245 `FROM busybox 3246 ADD foo /foo 3247 CMD ["cat", "/foo"]`, 3248 map[string]string{ 3249 "foo": "bar", 3250 }, 3251 ) 3252 defer ctx.Close() 3253 if err != nil { 3254 t.Fatal(err) 3255 } 3256 context, err := archive.Tar(ctx.Dir, compression) 3257 if err != nil { 3258 t.Fatalf("failed to build context tar: %v", err) 3259 } 3260 name := "contexttar" 3261 buildCmd := exec.Command(dockerBinary, "build", "-t", name, "-") 3262 defer deleteImages(name) 3263 buildCmd.Stdin = context 3264 3265 if out, _, err := runCommandWithOutput(buildCmd); err != nil { 3266 t.Fatalf("build failed to complete: %v %v", out, err) 3267 } 3268 logDone(fmt.Sprintf("build - build an image with a context tar, compression: %v", compression)) 3269 } 3270 3271 func TestBuildContextTarGzip(t *testing.T) { 3272 testContextTar(t, archive.Gzip) 3273 } 3274 3275 func TestBuildContextTarNoCompression(t *testing.T) { 3276 testContextTar(t, archive.Uncompressed) 3277 } 3278 3279 func TestBuildNoContext(t *testing.T) { 3280 buildCmd := exec.Command(dockerBinary, "build", "-t", "nocontext", "-") 3281 buildCmd.Stdin = strings.NewReader("FROM busybox\nCMD echo ok\n") 3282 3283 if out, _, err := runCommandWithOutput(buildCmd); err != nil { 3284 t.Fatalf("build failed to complete: %v %v", out, err) 3285 } 3286 3287 if out, _, err := dockerCmd(t, "run", "--rm", "nocontext"); out != "ok\n" || err != nil { 3288 t.Fatalf("run produced invalid output: %q, expected %q", out, "ok") 3289 } 3290 3291 deleteImages("nocontext") 3292 logDone("build - build an image with no context") 3293 } 3294 3295 // TODO: TestCaching 3296 func TestBuildADDLocalAndRemoteFilesWithoutCache(t *testing.T) { 3297 name := "testbuildaddlocalandremotefilewithoutcache" 3298 name2 := "testbuildaddlocalandremotefilewithoutcache2" 3299 defer deleteImages(name, name2) 3300 server, err := fakeStorage(map[string]string{ 3301 "baz": "hello", 3302 }) 3303 if err != nil { 3304 t.Fatal(err) 3305 } 3306 defer server.Close() 3307 3308 ctx, err := fakeContext(fmt.Sprintf(`FROM scratch 3309 MAINTAINER dockerio 3310 ADD foo /usr/lib/bla/bar 3311 ADD %s/baz /usr/lib/baz/quux`, server.URL()), 3312 map[string]string{ 3313 "foo": "hello world", 3314 }) 3315 if err != nil { 3316 t.Fatal(err) 3317 } 3318 defer ctx.Close() 3319 id1, err := buildImageFromContext(name, ctx, true) 3320 if err != nil { 3321 t.Fatal(err) 3322 } 3323 id2, err := buildImageFromContext(name2, ctx, false) 3324 if err != nil { 3325 t.Fatal(err) 3326 } 3327 if id1 == id2 { 3328 t.Fatal("The cache should have been invalided but hasn't.") 3329 } 3330 logDone("build - add local and remote file without cache") 3331 } 3332 3333 func TestBuildWithVolumeOwnership(t *testing.T) { 3334 name := "testbuildimg" 3335 defer deleteImages(name) 3336 3337 _, err := buildImage(name, 3338 `FROM busybox:latest 3339 RUN mkdir /test && chown daemon:daemon /test && chmod 0600 /test 3340 VOLUME /test`, 3341 true) 3342 3343 if err != nil { 3344 t.Fatal(err) 3345 } 3346 3347 cmd := exec.Command(dockerBinary, "run", "--rm", "testbuildimg", "ls", "-la", "/test") 3348 out, _, err := runCommandWithOutput(cmd) 3349 if err != nil { 3350 t.Fatal(out, err) 3351 } 3352 3353 if expected := "drw-------"; !strings.Contains(out, expected) { 3354 t.Fatalf("expected %s received %s", expected, out) 3355 } 3356 3357 if expected := "daemon daemon"; !strings.Contains(out, expected) { 3358 t.Fatalf("expected %s received %s", expected, out) 3359 } 3360 3361 logDone("build - volume ownership") 3362 } 3363 3364 // testing #1405 - config.Cmd does not get cleaned up if 3365 // utilizing cache 3366 func TestBuildEntrypointRunCleanup(t *testing.T) { 3367 name := "testbuildcmdcleanup" 3368 defer deleteImages(name) 3369 if _, err := buildImage(name, 3370 `FROM busybox 3371 RUN echo "hello"`, 3372 true); err != nil { 3373 t.Fatal(err) 3374 } 3375 3376 ctx, err := fakeContext(`FROM busybox 3377 RUN echo "hello" 3378 ADD foo /foo 3379 ENTRYPOINT ["/bin/echo"]`, 3380 map[string]string{ 3381 "foo": "hello", 3382 }) 3383 defer ctx.Close() 3384 if err != nil { 3385 t.Fatal(err) 3386 } 3387 if _, err := buildImageFromContext(name, ctx, true); err != nil { 3388 t.Fatal(err) 3389 } 3390 res, err := inspectField(name, "Config.Cmd") 3391 if err != nil { 3392 t.Fatal(err) 3393 } 3394 // Cmd must be cleaned up 3395 if expected := "<no value>"; res != expected { 3396 t.Fatalf("Cmd %s, expected %s", res, expected) 3397 } 3398 logDone("build - cleanup cmd after RUN") 3399 } 3400 3401 func TestBuildForbiddenContextPath(t *testing.T) { 3402 name := "testbuildforbidpath" 3403 defer deleteImages(name) 3404 ctx, err := fakeContext(`FROM scratch 3405 ADD ../../ test/ 3406 `, 3407 map[string]string{ 3408 "test.txt": "test1", 3409 "other.txt": "other", 3410 }) 3411 defer ctx.Close() 3412 if err != nil { 3413 t.Fatal(err) 3414 } 3415 3416 expected := "Forbidden path outside the build context: ../../ " 3417 if _, err := buildImageFromContext(name, ctx, true); err == nil || !strings.Contains(err.Error(), expected) { 3418 t.Fatalf("Wrong error: (should contain \"%s\") got:\n%v", expected, err) 3419 } 3420 3421 logDone("build - forbidden context path") 3422 } 3423 3424 func TestBuildADDFileNotFound(t *testing.T) { 3425 name := "testbuildaddnotfound" 3426 defer deleteImages(name) 3427 ctx, err := fakeContext(`FROM scratch 3428 ADD foo /usr/local/bar`, 3429 map[string]string{"bar": "hello"}) 3430 defer ctx.Close() 3431 if err != nil { 3432 t.Fatal(err) 3433 } 3434 if _, err := buildImageFromContext(name, ctx, true); err != nil { 3435 if !strings.Contains(err.Error(), "foo: no such file or directory") { 3436 t.Fatalf("Wrong error %v, must be about missing foo file or directory", err) 3437 } 3438 } else { 3439 t.Fatal("Error must not be nil") 3440 } 3441 logDone("build - add file not found") 3442 } 3443 3444 func TestBuildInheritance(t *testing.T) { 3445 name := "testbuildinheritance" 3446 defer deleteImages(name) 3447 3448 _, err := buildImage(name, 3449 `FROM scratch 3450 EXPOSE 2375`, 3451 true) 3452 if err != nil { 3453 t.Fatal(err) 3454 } 3455 ports1, err := inspectField(name, "Config.ExposedPorts") 3456 if err != nil { 3457 t.Fatal(err) 3458 } 3459 3460 _, err = buildImage(name, 3461 fmt.Sprintf(`FROM %s 3462 ENTRYPOINT ["/bin/echo"]`, name), 3463 true) 3464 if err != nil { 3465 t.Fatal(err) 3466 } 3467 3468 res, err := inspectField(name, "Config.Entrypoint") 3469 if err != nil { 3470 t.Fatal(err) 3471 } 3472 if expected := "[/bin/echo]"; res != expected { 3473 t.Fatalf("Entrypoint %s, expected %s", res, expected) 3474 } 3475 ports2, err := inspectField(name, "Config.ExposedPorts") 3476 if err != nil { 3477 t.Fatal(err) 3478 } 3479 if ports1 != ports2 { 3480 t.Fatalf("Ports must be same: %s != %s", ports1, ports2) 3481 } 3482 logDone("build - inheritance") 3483 } 3484 3485 func TestBuildFails(t *testing.T) { 3486 name := "testbuildfails" 3487 defer deleteImages(name) 3488 defer deleteAllContainers() 3489 _, err := buildImage(name, 3490 `FROM busybox 3491 RUN sh -c "exit 23"`, 3492 true) 3493 if err != nil { 3494 if !strings.Contains(err.Error(), "returned a non-zero code: 23") { 3495 t.Fatalf("Wrong error %v, must be about non-zero code 23", err) 3496 } 3497 } else { 3498 t.Fatal("Error must not be nil") 3499 } 3500 logDone("build - unsuccessful") 3501 } 3502 3503 func TestBuildFailsDockerfileEmpty(t *testing.T) { 3504 name := "testbuildfails" 3505 defer deleteImages(name) 3506 _, err := buildImage(name, ``, true) 3507 if err != nil { 3508 if !strings.Contains(err.Error(), "Dockerfile cannot be empty") { 3509 t.Fatalf("Wrong error %v, must be about empty Dockerfile", err) 3510 } 3511 } else { 3512 t.Fatal("Error must not be nil") 3513 } 3514 logDone("build - unsuccessful with empty dockerfile") 3515 } 3516 3517 func TestBuildOnBuild(t *testing.T) { 3518 name := "testbuildonbuild" 3519 defer deleteImages(name) 3520 _, err := buildImage(name, 3521 `FROM busybox 3522 ONBUILD RUN touch foobar`, 3523 true) 3524 if err != nil { 3525 t.Fatal(err) 3526 } 3527 _, err = buildImage(name, 3528 fmt.Sprintf(`FROM %s 3529 RUN [ -f foobar ]`, name), 3530 true) 3531 if err != nil { 3532 t.Fatal(err) 3533 } 3534 logDone("build - onbuild") 3535 } 3536 3537 func TestBuildOnBuildForbiddenChained(t *testing.T) { 3538 name := "testbuildonbuildforbiddenchained" 3539 defer deleteImages(name) 3540 _, err := buildImage(name, 3541 `FROM busybox 3542 ONBUILD ONBUILD RUN touch foobar`, 3543 true) 3544 if err != nil { 3545 if !strings.Contains(err.Error(), "Chaining ONBUILD via `ONBUILD ONBUILD` isn't allowed") { 3546 t.Fatalf("Wrong error %v, must be about chaining ONBUILD", err) 3547 } 3548 } else { 3549 t.Fatal("Error must not be nil") 3550 } 3551 logDone("build - onbuild forbidden chained") 3552 } 3553 3554 func TestBuildOnBuildForbiddenFrom(t *testing.T) { 3555 name := "testbuildonbuildforbiddenfrom" 3556 defer deleteImages(name) 3557 _, err := buildImage(name, 3558 `FROM busybox 3559 ONBUILD FROM scratch`, 3560 true) 3561 if err != nil { 3562 if !strings.Contains(err.Error(), "FROM isn't allowed as an ONBUILD trigger") { 3563 t.Fatalf("Wrong error %v, must be about FROM forbidden", err) 3564 } 3565 } else { 3566 t.Fatal("Error must not be nil") 3567 } 3568 logDone("build - onbuild forbidden from") 3569 } 3570 3571 func TestBuildOnBuildForbiddenMaintainer(t *testing.T) { 3572 name := "testbuildonbuildforbiddenmaintainer" 3573 defer deleteImages(name) 3574 _, err := buildImage(name, 3575 `FROM busybox 3576 ONBUILD MAINTAINER docker.io`, 3577 true) 3578 if err != nil { 3579 if !strings.Contains(err.Error(), "MAINTAINER isn't allowed as an ONBUILD trigger") { 3580 t.Fatalf("Wrong error %v, must be about MAINTAINER forbidden", err) 3581 } 3582 } else { 3583 t.Fatal("Error must not be nil") 3584 } 3585 logDone("build - onbuild forbidden maintainer") 3586 } 3587 3588 // gh #2446 3589 func TestBuildAddToSymlinkDest(t *testing.T) { 3590 name := "testbuildaddtosymlinkdest" 3591 defer deleteImages(name) 3592 ctx, err := fakeContext(`FROM busybox 3593 RUN mkdir /foo 3594 RUN ln -s /foo /bar 3595 ADD foo /bar/ 3596 RUN [ -f /bar/foo ] 3597 RUN [ -f /foo/foo ]`, 3598 map[string]string{ 3599 "foo": "hello", 3600 }) 3601 if err != nil { 3602 t.Fatal(err) 3603 } 3604 defer ctx.Close() 3605 if _, err := buildImageFromContext(name, ctx, true); err != nil { 3606 t.Fatal(err) 3607 } 3608 logDone("build - add to symlink destination") 3609 } 3610 3611 func TestBuildEscapeWhitespace(t *testing.T) { 3612 name := "testbuildescaping" 3613 defer deleteImages(name) 3614 3615 _, err := buildImage(name, ` 3616 FROM busybox 3617 MAINTAINER "Docker \ 3618 IO <io@\ 3619 docker.com>" 3620 `, true) 3621 3622 res, err := inspectField(name, "Author") 3623 3624 if err != nil { 3625 t.Fatal(err) 3626 } 3627 3628 if res != "\"Docker IO <io@docker.com>\"" { 3629 t.Fatalf("Parsed string did not match the escaped string. Got: %q", res) 3630 } 3631 3632 logDone("build - validate escaping whitespace") 3633 } 3634 3635 func TestBuildVerifyIntString(t *testing.T) { 3636 // Verify that strings that look like ints are still passed as strings 3637 name := "testbuildstringing" 3638 defer deleteImages(name) 3639 3640 _, err := buildImage(name, ` 3641 FROM busybox 3642 MAINTAINER 123 3643 `, true) 3644 3645 out, rc, err := runCommandWithOutput(exec.Command(dockerBinary, "inspect", name)) 3646 if rc != 0 || err != nil { 3647 t.Fatalf("Unexcepted error from inspect: rc: %v err: %v", rc, err) 3648 } 3649 3650 if !strings.Contains(out, "\"123\"") { 3651 t.Fatalf("Output does not contain the int as a string:\n%s", out) 3652 } 3653 3654 logDone("build - verify int/strings as strings") 3655 } 3656 3657 func TestBuildDockerignore(t *testing.T) { 3658 name := "testbuilddockerignore" 3659 defer deleteImages(name) 3660 dockerfile := ` 3661 FROM busybox 3662 ADD . /bla 3663 RUN [[ -f /bla/src/x.go ]] 3664 RUN [[ -f /bla/Makefile ]] 3665 RUN [[ ! -e /bla/src/_vendor ]] 3666 RUN [[ ! -e /bla/.gitignore ]] 3667 RUN [[ ! -e /bla/README.md ]] 3668 RUN [[ ! -e /bla/.git ]]` 3669 ctx, err := fakeContext(dockerfile, map[string]string{ 3670 "Makefile": "all:", 3671 ".git/HEAD": "ref: foo", 3672 "src/x.go": "package main", 3673 "src/_vendor/v.go": "package main", 3674 ".gitignore": "", 3675 "README.md": "readme", 3676 ".dockerignore": ".git\npkg\n.gitignore\nsrc/_vendor\n*.md", 3677 }) 3678 defer ctx.Close() 3679 if err != nil { 3680 t.Fatal(err) 3681 } 3682 if _, err := buildImageFromContext(name, ctx, true); err != nil { 3683 t.Fatal(err) 3684 } 3685 logDone("build - test .dockerignore") 3686 } 3687 3688 func TestBuildDockerignoreCleanPaths(t *testing.T) { 3689 name := "testbuilddockerignorecleanpaths" 3690 defer deleteImages(name) 3691 dockerfile := ` 3692 FROM busybox 3693 ADD . /tmp/ 3694 RUN (! ls /tmp/foo) && (! ls /tmp/foo2) && (! ls /tmp/dir1/foo)` 3695 ctx, err := fakeContext(dockerfile, map[string]string{ 3696 "foo": "foo", 3697 "foo2": "foo2", 3698 "dir1/foo": "foo in dir1", 3699 ".dockerignore": "./foo\ndir1//foo\n./dir1/../foo2", 3700 }) 3701 if err != nil { 3702 t.Fatal(err) 3703 } 3704 defer ctx.Close() 3705 if _, err := buildImageFromContext(name, ctx, true); err != nil { 3706 t.Fatal(err) 3707 } 3708 logDone("build - test .dockerignore with clean paths") 3709 } 3710 3711 func TestBuildDockerignoringDockerfile(t *testing.T) { 3712 name := "testbuilddockerignoredockerfile" 3713 defer deleteImages(name) 3714 dockerfile := ` 3715 FROM busybox 3716 ADD . /tmp/ 3717 RUN ! ls /tmp/Dockerfile 3718 RUN ls /tmp/.dockerignore` 3719 ctx, err := fakeContext(dockerfile, map[string]string{ 3720 "Dockerfile": dockerfile, 3721 ".dockerignore": "Dockerfile\n", 3722 }) 3723 if err != nil { 3724 t.Fatal(err) 3725 } 3726 defer ctx.Close() 3727 3728 if _, err = buildImageFromContext(name, ctx, true); err != nil { 3729 t.Fatalf("Didn't ignore Dockerfile correctly:%s", err) 3730 } 3731 3732 // now try it with ./Dockerfile 3733 ctx.Add(".dockerignore", "./Dockerfile\n") 3734 if _, err = buildImageFromContext(name, ctx, true); err != nil { 3735 t.Fatalf("Didn't ignore ./Dockerfile correctly:%s", err) 3736 } 3737 3738 logDone("build - test .dockerignore of Dockerfile") 3739 } 3740 3741 func TestBuildDockerignoringRenamedDockerfile(t *testing.T) { 3742 name := "testbuilddockerignoredockerfile" 3743 defer deleteImages(name) 3744 dockerfile := ` 3745 FROM busybox 3746 ADD . /tmp/ 3747 RUN ls /tmp/Dockerfile 3748 RUN ! ls /tmp/MyDockerfile 3749 RUN ls /tmp/.dockerignore` 3750 ctx, err := fakeContext(dockerfile, map[string]string{ 3751 "Dockerfile": "Should not use me", 3752 "MyDockerfile": dockerfile, 3753 ".dockerignore": "MyDockerfile\n", 3754 }) 3755 if err != nil { 3756 t.Fatal(err) 3757 } 3758 defer ctx.Close() 3759 3760 if _, err = buildImageFromContext(name, ctx, true); err != nil { 3761 t.Fatalf("Didn't ignore MyDockerfile correctly:%s", err) 3762 } 3763 3764 // now try it with ./MyDockerfile 3765 ctx.Add(".dockerignore", "./MyDockerfile\n") 3766 if _, err = buildImageFromContext(name, ctx, true); err != nil { 3767 t.Fatalf("Didn't ignore ./MyDockerfile correctly:%s", err) 3768 } 3769 3770 logDone("build - test .dockerignore of renamed Dockerfile") 3771 } 3772 3773 func TestBuildDockerignoringDockerignore(t *testing.T) { 3774 name := "testbuilddockerignoredockerignore" 3775 defer deleteImages(name) 3776 dockerfile := ` 3777 FROM busybox 3778 ADD . /tmp/ 3779 RUN ! ls /tmp/.dockerignore 3780 RUN ls /tmp/Dockerfile` 3781 ctx, err := fakeContext(dockerfile, map[string]string{ 3782 "Dockerfile": dockerfile, 3783 ".dockerignore": ".dockerignore\n", 3784 }) 3785 defer ctx.Close() 3786 if err != nil { 3787 t.Fatal(err) 3788 } 3789 if _, err = buildImageFromContext(name, ctx, true); err != nil { 3790 t.Fatalf("Didn't ignore .dockerignore correctly:%s", err) 3791 } 3792 logDone("build - test .dockerignore of .dockerignore") 3793 } 3794 3795 func TestBuildDockerignoreTouchDockerfile(t *testing.T) { 3796 var id1 string 3797 var id2 string 3798 3799 name := "testbuilddockerignoretouchdockerfile" 3800 defer deleteImages(name) 3801 dockerfile := ` 3802 FROM busybox 3803 ADD . /tmp/` 3804 ctx, err := fakeContext(dockerfile, map[string]string{ 3805 "Dockerfile": dockerfile, 3806 ".dockerignore": "Dockerfile\n", 3807 }) 3808 defer ctx.Close() 3809 if err != nil { 3810 t.Fatal(err) 3811 } 3812 3813 if id1, err = buildImageFromContext(name, ctx, true); err != nil { 3814 t.Fatalf("Didn't build it correctly:%s", err) 3815 } 3816 3817 if id2, err = buildImageFromContext(name, ctx, true); err != nil { 3818 t.Fatalf("Didn't build it correctly:%s", err) 3819 } 3820 if id1 != id2 { 3821 t.Fatalf("Didn't use the cache - 1") 3822 } 3823 3824 // Now make sure touching Dockerfile doesn't invalidate the cache 3825 if err = ctx.Add("Dockerfile", dockerfile+"\n# hi"); err != nil { 3826 t.Fatalf("Didn't add Dockerfile: %s", err) 3827 } 3828 if id2, err = buildImageFromContext(name, ctx, true); err != nil { 3829 t.Fatalf("Didn't build it correctly:%s", err) 3830 } 3831 if id1 != id2 { 3832 t.Fatalf("Didn't use the cache - 2") 3833 } 3834 3835 // One more time but just 'touch' it instead of changing the content 3836 if err = ctx.Add("Dockerfile", dockerfile+"\n# hi"); err != nil { 3837 t.Fatalf("Didn't add Dockerfile: %s", err) 3838 } 3839 if id2, err = buildImageFromContext(name, ctx, true); err != nil { 3840 t.Fatalf("Didn't build it correctly:%s", err) 3841 } 3842 if id1 != id2 { 3843 t.Fatalf("Didn't use the cache - 3") 3844 } 3845 3846 logDone("build - test .dockerignore touch dockerfile") 3847 } 3848 3849 func TestBuildDockerignoringWholeDir(t *testing.T) { 3850 name := "testbuilddockerignorewholedir" 3851 defer deleteImages(name) 3852 dockerfile := ` 3853 FROM busybox 3854 COPY . / 3855 RUN [[ ! -e /.gitignore ]] 3856 RUN [[ -f /Makefile ]]` 3857 ctx, err := fakeContext(dockerfile, map[string]string{ 3858 "Dockerfile": "FROM scratch", 3859 "Makefile": "all:", 3860 ".dockerignore": ".*\n", 3861 }) 3862 defer ctx.Close() 3863 if err != nil { 3864 t.Fatal(err) 3865 } 3866 if _, err = buildImageFromContext(name, ctx, true); err != nil { 3867 t.Fatal(err) 3868 } 3869 logDone("build - test .dockerignore whole dir with .*") 3870 } 3871 3872 func TestBuildLineBreak(t *testing.T) { 3873 name := "testbuildlinebreak" 3874 defer deleteImages(name) 3875 _, err := buildImage(name, 3876 `FROM busybox 3877 RUN sh -c 'echo root:testpass \ 3878 > /tmp/passwd' 3879 RUN mkdir -p /var/run/sshd 3880 RUN [ "$(cat /tmp/passwd)" = "root:testpass" ] 3881 RUN [ "$(ls -d /var/run/sshd)" = "/var/run/sshd" ]`, 3882 true) 3883 if err != nil { 3884 t.Fatal(err) 3885 } 3886 logDone("build - line break with \\") 3887 } 3888 3889 func TestBuildEOLInLine(t *testing.T) { 3890 name := "testbuildeolinline" 3891 defer deleteImages(name) 3892 _, err := buildImage(name, 3893 `FROM busybox 3894 RUN sh -c 'echo root:testpass > /tmp/passwd' 3895 RUN echo "foo \n bar"; echo "baz" 3896 RUN mkdir -p /var/run/sshd 3897 RUN [ "$(cat /tmp/passwd)" = "root:testpass" ] 3898 RUN [ "$(ls -d /var/run/sshd)" = "/var/run/sshd" ]`, 3899 true) 3900 if err != nil { 3901 t.Fatal(err) 3902 } 3903 logDone("build - end of line in dockerfile instruction") 3904 } 3905 3906 func TestBuildCommentsShebangs(t *testing.T) { 3907 name := "testbuildcomments" 3908 defer deleteImages(name) 3909 _, err := buildImage(name, 3910 `FROM busybox 3911 # This is an ordinary comment. 3912 RUN { echo '#!/bin/sh'; echo 'echo hello world'; } > /hello.sh 3913 RUN [ ! -x /hello.sh ] 3914 # comment with line break \ 3915 RUN chmod +x /hello.sh 3916 RUN [ -x /hello.sh ] 3917 RUN [ "$(cat /hello.sh)" = $'#!/bin/sh\necho hello world' ] 3918 RUN [ "$(/hello.sh)" = "hello world" ]`, 3919 true) 3920 if err != nil { 3921 t.Fatal(err) 3922 } 3923 logDone("build - comments and shebangs") 3924 } 3925 3926 func TestBuildUsersAndGroups(t *testing.T) { 3927 name := "testbuildusers" 3928 defer deleteImages(name) 3929 _, err := buildImage(name, 3930 `FROM busybox 3931 3932 # Make sure our defaults work 3933 RUN [ "$(id -u):$(id -g)/$(id -un):$(id -gn)" = '0:0/root:root' ] 3934 3935 # TODO decide if "args.user = strconv.Itoa(syscall.Getuid())" is acceptable behavior for changeUser in sysvinit instead of "return nil" when "USER" isn't specified (so that we get the proper group list even if that is the empty list, even in the default case of not supplying an explicit USER to run as, which implies USER 0) 3936 USER root 3937 RUN [ "$(id -G):$(id -Gn)" = '0 10:root wheel' ] 3938 3939 # Setup dockerio user and group 3940 RUN echo 'dockerio:x:1001:1001::/bin:/bin/false' >> /etc/passwd 3941 RUN echo 'dockerio:x:1001:' >> /etc/group 3942 3943 # Make sure we can switch to our user and all the information is exactly as we expect it to be 3944 USER dockerio 3945 RUN id -G 3946 RUN id -Gn 3947 RUN [ "$(id -u):$(id -g)/$(id -un):$(id -gn)/$(id -G):$(id -Gn)" = '1001:1001/dockerio:dockerio/1001:dockerio' ] 3948 3949 # Switch back to root and double check that worked exactly as we might expect it to 3950 USER root 3951 RUN [ "$(id -u):$(id -g)/$(id -un):$(id -gn)/$(id -G):$(id -Gn)" = '0:0/root:root/0 10:root wheel' ] 3952 3953 # Add a "supplementary" group for our dockerio user 3954 RUN echo 'supplementary:x:1002:dockerio' >> /etc/group 3955 3956 # ... and then go verify that we get it like we expect 3957 USER dockerio 3958 RUN [ "$(id -u):$(id -g)/$(id -un):$(id -gn)/$(id -G):$(id -Gn)" = '1001:1001/dockerio:dockerio/1001 1002:dockerio supplementary' ] 3959 USER 1001 3960 RUN [ "$(id -u):$(id -g)/$(id -un):$(id -gn)/$(id -G):$(id -Gn)" = '1001:1001/dockerio:dockerio/1001 1002:dockerio supplementary' ] 3961 3962 # super test the new "user:group" syntax 3963 USER dockerio:dockerio 3964 RUN [ "$(id -u):$(id -g)/$(id -un):$(id -gn)/$(id -G):$(id -Gn)" = '1001:1001/dockerio:dockerio/1001:dockerio' ] 3965 USER 1001:dockerio 3966 RUN [ "$(id -u):$(id -g)/$(id -un):$(id -gn)/$(id -G):$(id -Gn)" = '1001:1001/dockerio:dockerio/1001:dockerio' ] 3967 USER dockerio:1001 3968 RUN [ "$(id -u):$(id -g)/$(id -un):$(id -gn)/$(id -G):$(id -Gn)" = '1001:1001/dockerio:dockerio/1001:dockerio' ] 3969 USER 1001:1001 3970 RUN [ "$(id -u):$(id -g)/$(id -un):$(id -gn)/$(id -G):$(id -Gn)" = '1001:1001/dockerio:dockerio/1001:dockerio' ] 3971 USER dockerio:supplementary 3972 RUN [ "$(id -u):$(id -g)/$(id -un):$(id -gn)/$(id -G):$(id -Gn)" = '1001:1002/dockerio:supplementary/1002:supplementary' ] 3973 USER dockerio:1002 3974 RUN [ "$(id -u):$(id -g)/$(id -un):$(id -gn)/$(id -G):$(id -Gn)" = '1001:1002/dockerio:supplementary/1002:supplementary' ] 3975 USER 1001:supplementary 3976 RUN [ "$(id -u):$(id -g)/$(id -un):$(id -gn)/$(id -G):$(id -Gn)" = '1001:1002/dockerio:supplementary/1002:supplementary' ] 3977 USER 1001:1002 3978 RUN [ "$(id -u):$(id -g)/$(id -un):$(id -gn)/$(id -G):$(id -Gn)" = '1001:1002/dockerio:supplementary/1002:supplementary' ] 3979 3980 # make sure unknown uid/gid still works properly 3981 USER 1042:1043 3982 RUN [ "$(id -u):$(id -g)/$(id -un):$(id -gn)/$(id -G):$(id -Gn)" = '1042:1043/1042:1043/1043:1043' ]`, 3983 true) 3984 if err != nil { 3985 t.Fatal(err) 3986 } 3987 logDone("build - users and groups") 3988 } 3989 3990 func TestBuildEnvUsage(t *testing.T) { 3991 name := "testbuildenvusage" 3992 defer deleteImages(name) 3993 dockerfile := `FROM busybox 3994 ENV HOME /root 3995 ENV PATH $HOME/bin:$PATH 3996 ENV PATH /tmp:$PATH 3997 RUN [ "$PATH" = "/tmp:$HOME/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" ] 3998 ENV FOO /foo/baz 3999 ENV BAR /bar 4000 ENV BAZ $BAR 4001 ENV FOOPATH $PATH:$FOO 4002 RUN [ "$BAR" = "$BAZ" ] 4003 RUN [ "$FOOPATH" = "$PATH:/foo/baz" ] 4004 ENV FROM hello/docker/world 4005 ENV TO /docker/world/hello 4006 ADD $FROM $TO 4007 RUN [ "$(cat $TO)" = "hello" ] 4008 ENV abc=def 4009 ENV ghi=$abc 4010 RUN [ "$ghi" = "def" ] 4011 ` 4012 ctx, err := fakeContext(dockerfile, map[string]string{ 4013 "hello/docker/world": "hello", 4014 }) 4015 if err != nil { 4016 t.Fatal(err) 4017 } 4018 defer ctx.Close() 4019 4020 _, err = buildImageFromContext(name, ctx, true) 4021 if err != nil { 4022 t.Fatal(err) 4023 } 4024 logDone("build - environment variables usage") 4025 } 4026 4027 func TestBuildEnvUsage2(t *testing.T) { 4028 name := "testbuildenvusage2" 4029 defer deleteImages(name) 4030 dockerfile := `FROM busybox 4031 ENV abc=def 4032 RUN [ "$abc" = "def" ] 4033 ENV def="hello world" 4034 RUN [ "$def" = "hello world" ] 4035 ENV def=hello\ world 4036 RUN [ "$def" = "hello world" ] 4037 ENV v1=abc v2="hi there" 4038 RUN [ "$v1" = "abc" ] 4039 RUN [ "$v2" = "hi there" ] 4040 ENV v3='boogie nights' v4="with'quotes too" 4041 RUN [ "$v3" = "boogie nights" ] 4042 RUN [ "$v4" = "with'quotes too" ] 4043 ENV abc=zzz FROM=hello/docker/world 4044 ENV abc=zzz TO=/docker/world/hello 4045 ADD $FROM $TO 4046 RUN [ "$(cat $TO)" = "hello" ] 4047 ENV abc "zzz" 4048 RUN [ $abc = "zzz" ] 4049 ENV abc 'yyy' 4050 RUN [ $abc = 'yyy' ] 4051 ENV abc= 4052 RUN [ "$abc" = "" ] 4053 4054 # use grep to make sure if the builder substitutes \$foo by mistake 4055 # we don't get a false positive 4056 ENV abc=\$foo 4057 RUN [ "$abc" = "\$foo" ] && (echo "$abc" | grep foo) 4058 ENV abc \$foo 4059 RUN [ "$abc" = "\$foo" ] && (echo "$abc" | grep foo) 4060 4061 ENV abc=\'foo\' 4062 RUN [ "$abc" = "'foo'" ] 4063 ENV abc=\"foo\" 4064 RUN [ "$abc" = "\"foo\"" ] 4065 ENV abc "foo" 4066 RUN [ "$abc" = "foo" ] 4067 ENV abc 'foo' 4068 RUN [ "$abc" = 'foo' ] 4069 ENV abc \'foo\' 4070 RUN [ "$abc" = "'foo'" ] 4071 ENV abc \"foo\" 4072 RUN [ "$abc" = '"foo"' ] 4073 4074 ENV e1=bar 4075 ENV e2=$e1 4076 ENV e3=$e11 4077 ENV e4=\$e1 4078 ENV e5=\$e11 4079 RUN [ "$e0,$e1,$e2,$e3,$e4,$e5" = ',bar,bar,,$e1,$e11' ] 4080 4081 ENV ee1 bar 4082 ENV ee2 $ee1 4083 ENV ee3 $ee11 4084 ENV ee4 \$ee1 4085 ENV ee5 \$ee11 4086 RUN [ "$ee1,$ee2,$ee3,$ee4,$ee5" = 'bar,bar,,$ee1,$ee11' ] 4087 4088 ENV eee1="foo" 4089 ENV eee2='foo' 4090 ENV eee3 "foo" 4091 ENV eee4 'foo' 4092 RUN [ "$eee1,$eee2,$eee3,$eee4" = 'foo,foo,foo,foo' ] 4093 4094 ` 4095 ctx, err := fakeContext(dockerfile, map[string]string{ 4096 "hello/docker/world": "hello", 4097 }) 4098 if err != nil { 4099 t.Fatal(err) 4100 } 4101 defer ctx.Close() 4102 4103 _, err = buildImageFromContext(name, ctx, true) 4104 if err != nil { 4105 t.Fatal(err) 4106 } 4107 logDone("build - environment variables usage2") 4108 } 4109 4110 func TestBuildAddScript(t *testing.T) { 4111 name := "testbuildaddscript" 4112 defer deleteImages(name) 4113 dockerfile := ` 4114 FROM busybox 4115 ADD test /test 4116 RUN ["chmod","+x","/test"] 4117 RUN ["/test"] 4118 RUN [ "$(cat /testfile)" = 'test!' ]` 4119 ctx, err := fakeContext(dockerfile, map[string]string{ 4120 "test": "#!/bin/sh\necho 'test!' > /testfile", 4121 }) 4122 if err != nil { 4123 t.Fatal(err) 4124 } 4125 defer ctx.Close() 4126 4127 _, err = buildImageFromContext(name, ctx, true) 4128 if err != nil { 4129 t.Fatal(err) 4130 } 4131 logDone("build - add and run script") 4132 } 4133 4134 func TestBuildAddTar(t *testing.T) { 4135 name := "testbuildaddtar" 4136 defer deleteImages(name) 4137 4138 ctx := func() *FakeContext { 4139 dockerfile := ` 4140 FROM busybox 4141 ADD test.tar / 4142 RUN cat /test/foo | grep Hi 4143 ADD test.tar /test.tar 4144 RUN cat /test.tar/test/foo | grep Hi 4145 ADD test.tar /unlikely-to-exist 4146 RUN cat /unlikely-to-exist/test/foo | grep Hi 4147 ADD test.tar /unlikely-to-exist-trailing-slash/ 4148 RUN cat /unlikely-to-exist-trailing-slash/test/foo | grep Hi 4149 RUN mkdir /existing-directory 4150 ADD test.tar /existing-directory 4151 RUN cat /existing-directory/test/foo | grep Hi 4152 ADD test.tar /existing-directory-trailing-slash/ 4153 RUN cat /existing-directory-trailing-slash/test/foo | grep Hi` 4154 tmpDir, err := ioutil.TempDir("", "fake-context") 4155 testTar, err := os.Create(filepath.Join(tmpDir, "test.tar")) 4156 if err != nil { 4157 t.Fatalf("failed to create test.tar archive: %v", err) 4158 } 4159 defer testTar.Close() 4160 4161 tw := tar.NewWriter(testTar) 4162 4163 if err := tw.WriteHeader(&tar.Header{ 4164 Name: "test/foo", 4165 Size: 2, 4166 }); err != nil { 4167 t.Fatalf("failed to write tar file header: %v", err) 4168 } 4169 if _, err := tw.Write([]byte("Hi")); err != nil { 4170 t.Fatalf("failed to write tar file content: %v", err) 4171 } 4172 if err := tw.Close(); err != nil { 4173 t.Fatalf("failed to close tar archive: %v", err) 4174 } 4175 4176 if err := ioutil.WriteFile(filepath.Join(tmpDir, "Dockerfile"), []byte(dockerfile), 0644); err != nil { 4177 t.Fatalf("failed to open destination dockerfile: %v", err) 4178 } 4179 return fakeContextFromDir(tmpDir) 4180 }() 4181 defer ctx.Close() 4182 4183 if _, err := buildImageFromContext(name, ctx, true); err != nil { 4184 t.Fatalf("build failed to complete for TestBuildAddTar: %v", err) 4185 } 4186 4187 logDone("build - ADD tar") 4188 } 4189 4190 func TestBuildAddTarXz(t *testing.T) { 4191 name := "testbuildaddtarxz" 4192 defer deleteImages(name) 4193 4194 ctx := func() *FakeContext { 4195 dockerfile := ` 4196 FROM busybox 4197 ADD test.tar.xz / 4198 RUN cat /test/foo | grep Hi` 4199 tmpDir, err := ioutil.TempDir("", "fake-context") 4200 testTar, err := os.Create(filepath.Join(tmpDir, "test.tar")) 4201 if err != nil { 4202 t.Fatalf("failed to create test.tar archive: %v", err) 4203 } 4204 defer testTar.Close() 4205 4206 tw := tar.NewWriter(testTar) 4207 4208 if err := tw.WriteHeader(&tar.Header{ 4209 Name: "test/foo", 4210 Size: 2, 4211 }); err != nil { 4212 t.Fatalf("failed to write tar file header: %v", err) 4213 } 4214 if _, err := tw.Write([]byte("Hi")); err != nil { 4215 t.Fatalf("failed to write tar file content: %v", err) 4216 } 4217 if err := tw.Close(); err != nil { 4218 t.Fatalf("failed to close tar archive: %v", err) 4219 } 4220 xzCompressCmd := exec.Command("xz", "-k", "test.tar") 4221 xzCompressCmd.Dir = tmpDir 4222 out, _, err := runCommandWithOutput(xzCompressCmd) 4223 if err != nil { 4224 t.Fatal(err, out) 4225 } 4226 4227 if err := ioutil.WriteFile(filepath.Join(tmpDir, "Dockerfile"), []byte(dockerfile), 0644); err != nil { 4228 t.Fatalf("failed to open destination dockerfile: %v", err) 4229 } 4230 return fakeContextFromDir(tmpDir) 4231 }() 4232 4233 defer ctx.Close() 4234 4235 if _, err := buildImageFromContext(name, ctx, true); err != nil { 4236 t.Fatalf("build failed to complete for TestBuildAddTarXz: %v", err) 4237 } 4238 4239 logDone("build - ADD tar.xz") 4240 } 4241 4242 func TestBuildAddTarXzGz(t *testing.T) { 4243 name := "testbuildaddtarxzgz" 4244 defer deleteImages(name) 4245 4246 ctx := func() *FakeContext { 4247 dockerfile := ` 4248 FROM busybox 4249 ADD test.tar.xz.gz / 4250 RUN ls /test.tar.xz.gz` 4251 tmpDir, err := ioutil.TempDir("", "fake-context") 4252 testTar, err := os.Create(filepath.Join(tmpDir, "test.tar")) 4253 if err != nil { 4254 t.Fatalf("failed to create test.tar archive: %v", err) 4255 } 4256 defer testTar.Close() 4257 4258 tw := tar.NewWriter(testTar) 4259 4260 if err := tw.WriteHeader(&tar.Header{ 4261 Name: "test/foo", 4262 Size: 2, 4263 }); err != nil { 4264 t.Fatalf("failed to write tar file header: %v", err) 4265 } 4266 if _, err := tw.Write([]byte("Hi")); err != nil { 4267 t.Fatalf("failed to write tar file content: %v", err) 4268 } 4269 if err := tw.Close(); err != nil { 4270 t.Fatalf("failed to close tar archive: %v", err) 4271 } 4272 4273 xzCompressCmd := exec.Command("xz", "-k", "test.tar") 4274 xzCompressCmd.Dir = tmpDir 4275 out, _, err := runCommandWithOutput(xzCompressCmd) 4276 if err != nil { 4277 t.Fatal(err, out) 4278 } 4279 4280 gzipCompressCmd := exec.Command("gzip", "test.tar.xz") 4281 gzipCompressCmd.Dir = tmpDir 4282 out, _, err = runCommandWithOutput(gzipCompressCmd) 4283 if err != nil { 4284 t.Fatal(err, out) 4285 } 4286 4287 if err := ioutil.WriteFile(filepath.Join(tmpDir, "Dockerfile"), []byte(dockerfile), 0644); err != nil { 4288 t.Fatalf("failed to open destination dockerfile: %v", err) 4289 } 4290 return fakeContextFromDir(tmpDir) 4291 }() 4292 4293 defer ctx.Close() 4294 4295 if _, err := buildImageFromContext(name, ctx, true); err != nil { 4296 t.Fatalf("build failed to complete for TestBuildAddTarXz: %v", err) 4297 } 4298 4299 logDone("build - ADD tar.xz.gz") 4300 } 4301 4302 func TestBuildFromGIT(t *testing.T) { 4303 name := "testbuildfromgit" 4304 defer deleteImages(name) 4305 git, err := fakeGIT("repo", map[string]string{ 4306 "Dockerfile": `FROM busybox 4307 ADD first /first 4308 RUN [ -f /first ] 4309 MAINTAINER docker`, 4310 "first": "test git data", 4311 }, true) 4312 if err != nil { 4313 t.Fatal(err) 4314 } 4315 defer git.Close() 4316 4317 _, err = buildImageFromPath(name, git.RepoURL, true) 4318 if err != nil { 4319 t.Fatal(err) 4320 } 4321 res, err := inspectField(name, "Author") 4322 if err != nil { 4323 t.Fatal(err) 4324 } 4325 if res != "docker" { 4326 t.Fatalf("Maintainer should be docker, got %s", res) 4327 } 4328 logDone("build - build from GIT") 4329 } 4330 4331 func TestBuildCleanupCmdOnEntrypoint(t *testing.T) { 4332 name := "testbuildcmdcleanuponentrypoint" 4333 defer deleteImages(name) 4334 if _, err := buildImage(name, 4335 `FROM scratch 4336 CMD ["test"] 4337 ENTRYPOINT ["echo"]`, 4338 true); err != nil { 4339 t.Fatal(err) 4340 } 4341 if _, err := buildImage(name, 4342 fmt.Sprintf(`FROM %s 4343 ENTRYPOINT ["cat"]`, name), 4344 true); err != nil { 4345 t.Fatal(err) 4346 } 4347 res, err := inspectField(name, "Config.Cmd") 4348 if err != nil { 4349 t.Fatal(err) 4350 } 4351 if expected := "<no value>"; res != expected { 4352 t.Fatalf("Cmd %s, expected %s", res, expected) 4353 } 4354 res, err = inspectField(name, "Config.Entrypoint") 4355 if err != nil { 4356 t.Fatal(err) 4357 } 4358 if expected := "[cat]"; res != expected { 4359 t.Fatalf("Entrypoint %s, expected %s", res, expected) 4360 } 4361 logDone("build - cleanup cmd on ENTRYPOINT") 4362 } 4363 4364 func TestBuildClearCmd(t *testing.T) { 4365 name := "testbuildclearcmd" 4366 defer deleteImages(name) 4367 _, err := buildImage(name, 4368 `From scratch 4369 ENTRYPOINT ["/bin/bash"] 4370 CMD []`, 4371 true) 4372 if err != nil { 4373 t.Fatal(err) 4374 } 4375 res, err := inspectFieldJSON(name, "Config.Cmd") 4376 if err != nil { 4377 t.Fatal(err) 4378 } 4379 if res != "[]" { 4380 t.Fatalf("Cmd %s, expected %s", res, "[]") 4381 } 4382 logDone("build - clearcmd") 4383 } 4384 4385 func TestBuildEmptyCmd(t *testing.T) { 4386 name := "testbuildemptycmd" 4387 defer deleteImages(name) 4388 if _, err := buildImage(name, "FROM scratch\nMAINTAINER quux\n", true); err != nil { 4389 t.Fatal(err) 4390 } 4391 res, err := inspectFieldJSON(name, "Config.Cmd") 4392 if err != nil { 4393 t.Fatal(err) 4394 } 4395 if res != "null" { 4396 t.Fatalf("Cmd %s, expected %s", res, "null") 4397 } 4398 logDone("build - empty cmd") 4399 } 4400 4401 func TestBuildOnBuildOutput(t *testing.T) { 4402 name := "testbuildonbuildparent" 4403 defer deleteImages(name) 4404 if _, err := buildImage(name, "FROM busybox\nONBUILD RUN echo foo\n", true); err != nil { 4405 t.Fatal(err) 4406 } 4407 4408 childname := "testbuildonbuildchild" 4409 defer deleteImages(childname) 4410 4411 _, out, err := buildImageWithOut(name, "FROM "+name+"\nMAINTAINER quux\n", true) 4412 if err != nil { 4413 t.Fatal(err) 4414 } 4415 4416 if !strings.Contains(out, "Trigger 0, RUN echo foo") { 4417 t.Fatal("failed to find the ONBUILD output", out) 4418 } 4419 4420 logDone("build - onbuild output") 4421 } 4422 4423 func TestBuildInvalidTag(t *testing.T) { 4424 name := "abcd:" + makeRandomString(200) 4425 defer deleteImages(name) 4426 _, out, err := buildImageWithOut(name, "FROM scratch\nMAINTAINER quux\n", true) 4427 // if the error doesnt check for illegal tag name, or the image is built 4428 // then this should fail 4429 if !strings.Contains(out, "Illegal tag name") || strings.Contains(out, "Sending build context to Docker daemon") { 4430 t.Fatalf("failed to stop before building. Error: %s, Output: %s", err, out) 4431 } 4432 logDone("build - invalid tag") 4433 } 4434 4435 func TestBuildCmdShDashC(t *testing.T) { 4436 name := "testbuildcmdshc" 4437 defer deleteImages(name) 4438 if _, err := buildImage(name, "FROM busybox\nCMD echo cmd\n", true); err != nil { 4439 t.Fatal(err) 4440 } 4441 4442 res, err := inspectFieldJSON(name, "Config.Cmd") 4443 if err != nil { 4444 t.Fatal(err, res) 4445 } 4446 4447 expected := `["/bin/sh","-c","echo cmd"]` 4448 4449 if res != expected { 4450 t.Fatalf("Expected value %s not in Config.Cmd: %s", expected, res) 4451 } 4452 4453 logDone("build - cmd should have sh -c for non-json") 4454 } 4455 4456 func TestBuildCmdSpaces(t *testing.T) { 4457 // Test to make sure that when we strcat arrays we take into account 4458 // the arg separator to make sure ["echo","hi"] and ["echo hi"] don't 4459 // look the same 4460 name := "testbuildcmdspaces" 4461 defer deleteImages(name) 4462 var id1 string 4463 var id2 string 4464 var err error 4465 4466 if id1, err = buildImage(name, "FROM busybox\nCMD [\"echo hi\"]\n", true); err != nil { 4467 t.Fatal(err) 4468 } 4469 4470 if id2, err = buildImage(name, "FROM busybox\nCMD [\"echo\", \"hi\"]\n", true); err != nil { 4471 t.Fatal(err) 4472 } 4473 4474 if id1 == id2 { 4475 t.Fatal("Should not have resulted in the same CMD") 4476 } 4477 4478 // Now do the same with ENTRYPOINT 4479 if id1, err = buildImage(name, "FROM busybox\nENTRYPOINT [\"echo hi\"]\n", true); err != nil { 4480 t.Fatal(err) 4481 } 4482 4483 if id2, err = buildImage(name, "FROM busybox\nENTRYPOINT [\"echo\", \"hi\"]\n", true); err != nil { 4484 t.Fatal(err) 4485 } 4486 4487 if id1 == id2 { 4488 t.Fatal("Should not have resulted in the same ENTRYPOINT") 4489 } 4490 4491 logDone("build - cmd with spaces") 4492 } 4493 4494 func TestBuildCmdJSONNoShDashC(t *testing.T) { 4495 name := "testbuildcmdjson" 4496 defer deleteImages(name) 4497 if _, err := buildImage(name, "FROM busybox\nCMD [\"echo\", \"cmd\"]", true); err != nil { 4498 t.Fatal(err) 4499 } 4500 4501 res, err := inspectFieldJSON(name, "Config.Cmd") 4502 if err != nil { 4503 t.Fatal(err, res) 4504 } 4505 4506 expected := `["echo","cmd"]` 4507 4508 if res != expected { 4509 t.Fatalf("Expected value %s not in Config.Cmd: %s", expected, res) 4510 } 4511 4512 logDone("build - cmd should not have /bin/sh -c for json") 4513 } 4514 4515 func TestBuildErrorInvalidInstruction(t *testing.T) { 4516 name := "testbuildignoreinvalidinstruction" 4517 defer deleteImages(name) 4518 4519 out, _, err := buildImageWithOut(name, "FROM busybox\nfoo bar", true) 4520 if err == nil { 4521 t.Fatalf("Should have failed: %s", out) 4522 } 4523 4524 logDone("build - error invalid Dockerfile instruction") 4525 } 4526 4527 func TestBuildEntrypointInheritance(t *testing.T) { 4528 defer deleteImages("parent", "child") 4529 defer deleteAllContainers() 4530 4531 if _, err := buildImage("parent", ` 4532 FROM busybox 4533 ENTRYPOINT exit 130 4534 `, true); err != nil { 4535 t.Fatal(err) 4536 } 4537 4538 status, _ := runCommand(exec.Command(dockerBinary, "run", "parent")) 4539 4540 if status != 130 { 4541 t.Fatalf("expected exit code 130 but received %d", status) 4542 } 4543 4544 if _, err := buildImage("child", ` 4545 FROM parent 4546 ENTRYPOINT exit 5 4547 `, true); err != nil { 4548 t.Fatal(err) 4549 } 4550 4551 status, _ = runCommand(exec.Command(dockerBinary, "run", "child")) 4552 4553 if status != 5 { 4554 t.Fatalf("expected exit code 5 but received %d", status) 4555 } 4556 4557 logDone("build - clear entrypoint") 4558 } 4559 4560 func TestBuildEntrypointInheritanceInspect(t *testing.T) { 4561 var ( 4562 name = "testbuildepinherit" 4563 name2 = "testbuildepinherit2" 4564 expected = `["/bin/sh","-c","echo quux"]` 4565 ) 4566 4567 defer deleteImages(name, name2) 4568 defer deleteAllContainers() 4569 4570 if _, err := buildImage(name, "FROM busybox\nENTRYPOINT /foo/bar", true); err != nil { 4571 t.Fatal(err) 4572 } 4573 4574 if _, err := buildImage(name2, fmt.Sprintf("FROM %s\nENTRYPOINT echo quux", name), true); err != nil { 4575 t.Fatal(err) 4576 } 4577 4578 res, err := inspectFieldJSON(name2, "Config.Entrypoint") 4579 if err != nil { 4580 t.Fatal(err, res) 4581 } 4582 4583 if res != expected { 4584 t.Fatalf("Expected value %s not in Config.Entrypoint: %s", expected, res) 4585 } 4586 4587 out, _, err := runCommandWithOutput(exec.Command(dockerBinary, "run", "-t", name2)) 4588 if err != nil { 4589 t.Fatal(err, out) 4590 } 4591 4592 expected = "quux" 4593 4594 if strings.TrimSpace(out) != expected { 4595 t.Fatalf("Expected output is %s, got %s", expected, out) 4596 } 4597 4598 logDone("build - entrypoint override inheritance properly") 4599 } 4600 4601 func TestBuildRunShEntrypoint(t *testing.T) { 4602 name := "testbuildentrypoint" 4603 defer deleteImages(name) 4604 _, err := buildImage(name, 4605 `FROM busybox 4606 ENTRYPOINT /bin/echo`, 4607 true) 4608 if err != nil { 4609 t.Fatal(err) 4610 } 4611 4612 out, _, err := runCommandWithOutput(exec.Command(dockerBinary, "run", "--rm", name)) 4613 4614 if err != nil { 4615 t.Fatal(err, out) 4616 } 4617 4618 logDone("build - entrypoint with /bin/echo running successfully") 4619 } 4620 4621 func TestBuildExoticShellInterpolation(t *testing.T) { 4622 name := "testbuildexoticshellinterpolation" 4623 defer deleteImages(name) 4624 4625 _, err := buildImage(name, ` 4626 FROM busybox 4627 4628 ENV SOME_VAR a.b.c 4629 4630 RUN [ "$SOME_VAR" = 'a.b.c' ] 4631 RUN [ "${SOME_VAR}" = 'a.b.c' ] 4632 RUN [ "${SOME_VAR%.*}" = 'a.b' ] 4633 RUN [ "${SOME_VAR%%.*}" = 'a' ] 4634 RUN [ "${SOME_VAR#*.}" = 'b.c' ] 4635 RUN [ "${SOME_VAR##*.}" = 'c' ] 4636 RUN [ "${SOME_VAR/c/d}" = 'a.b.d' ] 4637 RUN [ "${#SOME_VAR}" = '5' ] 4638 4639 RUN [ "${SOME_UNSET_VAR:-$SOME_VAR}" = 'a.b.c' ] 4640 RUN [ "${SOME_VAR:+Version: ${SOME_VAR}}" = 'Version: a.b.c' ] 4641 RUN [ "${SOME_UNSET_VAR:+${SOME_VAR}}" = '' ] 4642 RUN [ "${SOME_UNSET_VAR:-${SOME_VAR:-d.e.f}}" = 'a.b.c' ] 4643 `, false) 4644 if err != nil { 4645 t.Fatal(err) 4646 } 4647 4648 logDone("build - exotic shell interpolation") 4649 } 4650 4651 func TestBuildVerifySingleQuoteFails(t *testing.T) { 4652 // This testcase is supposed to generate an error because the 4653 // JSON array we're passing in on the CMD uses single quotes instead 4654 // of double quotes (per the JSON spec). This means we interpret it 4655 // as a "string" insead of "JSON array" and pass it on to "sh -c" and 4656 // it should barf on it. 4657 name := "testbuildsinglequotefails" 4658 defer deleteImages(name) 4659 defer deleteAllContainers() 4660 4661 _, err := buildImage(name, 4662 `FROM busybox 4663 CMD [ '/bin/sh', '-c', 'echo hi' ]`, 4664 true) 4665 _, _, err = runCommandWithOutput(exec.Command(dockerBinary, "run", "--rm", name)) 4666 4667 if err == nil { 4668 t.Fatal("The image was not supposed to be able to run") 4669 } 4670 4671 logDone("build - verify single quotes break the build") 4672 } 4673 4674 func TestBuildVerboseOut(t *testing.T) { 4675 name := "testbuildverboseout" 4676 defer deleteImages(name) 4677 4678 _, out, err := buildImageWithOut(name, 4679 `FROM busybox 4680 RUN echo 123`, 4681 false) 4682 4683 if err != nil { 4684 t.Fatal(err) 4685 } 4686 if !strings.Contains(out, "\n123\n") { 4687 t.Fatalf("Output should contain %q: %q", "123", out) 4688 } 4689 4690 logDone("build - verbose output from commands") 4691 } 4692 4693 func TestBuildWithTabs(t *testing.T) { 4694 name := "testbuildwithtabs" 4695 defer deleteImages(name) 4696 _, err := buildImage(name, 4697 "FROM busybox\nRUN echo\tone\t\ttwo", true) 4698 if err != nil { 4699 t.Fatal(err) 4700 } 4701 res, err := inspectFieldJSON(name, "ContainerConfig.Cmd") 4702 if err != nil { 4703 t.Fatal(err) 4704 } 4705 expected1 := `["/bin/sh","-c","echo\tone\t\ttwo"]` 4706 expected2 := `["/bin/sh","-c","echo\u0009one\u0009\u0009two"]` // syntactically equivalent, and what Go 1.3 generates 4707 if res != expected1 && res != expected2 { 4708 t.Fatalf("Missing tabs.\nGot: %s\nExp: %s or %s", res, expected1, expected2) 4709 } 4710 logDone("build - with tabs") 4711 } 4712 4713 func TestBuildLabels(t *testing.T) { 4714 name := "testbuildlabel" 4715 expected := `{"License":"GPL","Vendor":"Acme"}` 4716 defer deleteImages(name) 4717 _, err := buildImage(name, 4718 `FROM busybox 4719 LABEL Vendor=Acme 4720 LABEL License GPL`, 4721 true) 4722 if err != nil { 4723 t.Fatal(err) 4724 } 4725 res, err := inspectFieldJSON(name, "Config.Labels") 4726 if err != nil { 4727 t.Fatal(err) 4728 } 4729 if res != expected { 4730 t.Fatalf("Labels %s, expected %s", res, expected) 4731 } 4732 logDone("build - label") 4733 } 4734 4735 func TestBuildLabelsCache(t *testing.T) { 4736 name := "testbuildlabelcache" 4737 defer deleteImages(name) 4738 4739 id1, err := buildImage(name, 4740 `FROM busybox 4741 LABEL Vendor=Acme`, false) 4742 if err != nil { 4743 t.Fatalf("Build 1 should have worked: %v", err) 4744 } 4745 4746 id2, err := buildImage(name, 4747 `FROM busybox 4748 LABEL Vendor=Acme`, true) 4749 if err != nil || id1 != id2 { 4750 t.Fatalf("Build 2 should have worked & used cache(%s,%s): %v", id1, id2, err) 4751 } 4752 4753 id2, err = buildImage(name, 4754 `FROM busybox 4755 LABEL Vendor=Acme1`, true) 4756 if err != nil || id1 == id2 { 4757 t.Fatalf("Build 3 should have worked & NOT used cache(%s,%s): %v", id1, id2, err) 4758 } 4759 4760 id2, err = buildImage(name, 4761 `FROM busybox 4762 LABEL Vendor Acme`, true) // Note: " " and "=" should be same 4763 if err != nil || id1 != id2 { 4764 t.Fatalf("Build 4 should have worked & used cache(%s,%s): %v", id1, id2, err) 4765 } 4766 4767 // Now make sure the cache isn't used by mistake 4768 id1, err = buildImage(name, 4769 `FROM busybox 4770 LABEL f1=b1 f2=b2`, false) 4771 if err != nil { 4772 t.Fatalf("Build 5 should have worked: %q", err) 4773 } 4774 4775 id2, err = buildImage(name, 4776 `FROM busybox 4777 LABEL f1="b1 f2=b2"`, true) 4778 if err != nil || id1 == id2 { 4779 t.Fatalf("Build 6 should have worked & NOT used the cache(%s,%s): %q", id1, id2, err) 4780 } 4781 4782 logDone("build - label cache") 4783 } 4784 4785 func TestBuildStderr(t *testing.T) { 4786 // This test just makes sure that no non-error output goes 4787 // to stderr 4788 name := "testbuildstderr" 4789 defer deleteImages(name) 4790 _, _, stderr, err := buildImageWithStdoutStderr(name, 4791 "FROM busybox\nRUN echo one", true) 4792 if err != nil { 4793 t.Fatal(err) 4794 } 4795 4796 if runtime.GOOS == "windows" { 4797 // stderr might contain a security warning on windows 4798 lines := strings.Split(stderr, "\n") 4799 for _, v := range lines { 4800 if v != "" && !strings.Contains(v, "SECURITY WARNING:") { 4801 t.Fatalf("Stderr contains unexpected output line: %q", v) 4802 } 4803 } 4804 } else { 4805 if stderr != "" { 4806 t.Fatalf("Stderr should have been empty, instead its: %q", stderr) 4807 } 4808 } 4809 logDone("build - testing stderr") 4810 } 4811 4812 func TestBuildChownSingleFile(t *testing.T) { 4813 testRequires(t, UnixCli) // test uses chown: not available on windows 4814 4815 name := "testbuildchownsinglefile" 4816 defer deleteImages(name) 4817 4818 ctx, err := fakeContext(` 4819 FROM busybox 4820 COPY test / 4821 RUN ls -l /test 4822 RUN [ $(ls -l /test | awk '{print $3":"$4}') = 'root:root' ] 4823 `, map[string]string{ 4824 "test": "test", 4825 }) 4826 if err != nil { 4827 t.Fatal(err) 4828 } 4829 defer ctx.Close() 4830 4831 if err := os.Chown(filepath.Join(ctx.Dir, "test"), 4242, 4242); err != nil { 4832 t.Fatal(err) 4833 } 4834 4835 if _, err := buildImageFromContext(name, ctx, true); err != nil { 4836 t.Fatal(err) 4837 } 4838 4839 logDone("build - change permission on single file") 4840 } 4841 4842 func TestBuildSymlinkBreakout(t *testing.T) { 4843 name := "testbuildsymlinkbreakout" 4844 tmpdir, err := ioutil.TempDir("", name) 4845 if err != nil { 4846 t.Fatal(err) 4847 } 4848 defer os.RemoveAll(tmpdir) 4849 ctx := filepath.Join(tmpdir, "context") 4850 if err := os.MkdirAll(ctx, 0755); err != nil { 4851 t.Fatal(err) 4852 } 4853 if err := ioutil.WriteFile(filepath.Join(ctx, "Dockerfile"), []byte(` 4854 from busybox 4855 add symlink.tar / 4856 add inject /symlink/ 4857 `), 0644); err != nil { 4858 t.Fatal(err) 4859 } 4860 inject := filepath.Join(ctx, "inject") 4861 if err := ioutil.WriteFile(inject, nil, 0644); err != nil { 4862 t.Fatal(err) 4863 } 4864 f, err := os.Create(filepath.Join(ctx, "symlink.tar")) 4865 if err != nil { 4866 t.Fatal(err) 4867 } 4868 w := tar.NewWriter(f) 4869 w.WriteHeader(&tar.Header{ 4870 Name: "symlink2", 4871 Typeflag: tar.TypeSymlink, 4872 Linkname: "/../../../../../../../../../../../../../../", 4873 Uid: os.Getuid(), 4874 Gid: os.Getgid(), 4875 }) 4876 w.WriteHeader(&tar.Header{ 4877 Name: "symlink", 4878 Typeflag: tar.TypeSymlink, 4879 Linkname: filepath.Join("symlink2", tmpdir), 4880 Uid: os.Getuid(), 4881 Gid: os.Getgid(), 4882 }) 4883 w.Close() 4884 f.Close() 4885 if _, err := buildImageFromContext(name, fakeContextFromDir(ctx), false); err != nil { 4886 t.Fatal(err) 4887 } 4888 if _, err := os.Lstat(filepath.Join(tmpdir, "inject")); err == nil { 4889 t.Fatal("symlink breakout - inject") 4890 } else if !os.IsNotExist(err) { 4891 t.Fatalf("unexpected error: %v", err) 4892 } 4893 logDone("build - symlink breakout") 4894 } 4895 4896 func TestBuildXZHost(t *testing.T) { 4897 name := "testbuildxzhost" 4898 defer deleteImages(name) 4899 4900 ctx, err := fakeContext(` 4901 FROM busybox 4902 ADD xz /usr/local/sbin/ 4903 RUN chmod 755 /usr/local/sbin/xz 4904 ADD test.xz / 4905 RUN [ ! -e /injected ]`, 4906 map[string]string{ 4907 "test.xz": "\xfd\x37\x7a\x58\x5a\x00\x00\x04\xe6\xd6\xb4\x46\x02\x00" + 4908 "\x21\x01\x16\x00\x00\x00\x74\x2f\xe5\xa3\x01\x00\x3f\xfd" + 4909 "\x37\x7a\x58\x5a\x00\x00\x04\xe6\xd6\xb4\x46\x02\x00\x21", 4910 "xz": "#!/bin/sh\ntouch /injected", 4911 }) 4912 4913 if err != nil { 4914 t.Fatal(err) 4915 } 4916 defer ctx.Close() 4917 4918 if _, err := buildImageFromContext(name, ctx, true); err != nil { 4919 t.Fatal(err) 4920 } 4921 4922 logDone("build - xz host is being used") 4923 } 4924 4925 func TestBuildVolumesRetainContents(t *testing.T) { 4926 var ( 4927 name = "testbuildvolumescontent" 4928 expected = "some text" 4929 ) 4930 defer deleteImages(name) 4931 ctx, err := fakeContext(` 4932 FROM busybox 4933 COPY content /foo/file 4934 VOLUME /foo 4935 CMD cat /foo/file`, 4936 map[string]string{ 4937 "content": expected, 4938 }) 4939 if err != nil { 4940 t.Fatal(err) 4941 } 4942 defer ctx.Close() 4943 4944 if _, err := buildImageFromContext(name, ctx, false); err != nil { 4945 t.Fatal(err) 4946 } 4947 4948 out, _, err := runCommandWithOutput(exec.Command(dockerBinary, "run", "--rm", name)) 4949 if err != nil { 4950 t.Fatal(err) 4951 } 4952 if out != expected { 4953 t.Fatalf("expected file contents for /foo/file to be %q but received %q", expected, out) 4954 } 4955 4956 logDone("build - volumes retain contents in build") 4957 } 4958 4959 func TestBuildRenamedDockerfile(t *testing.T) { 4960 defer deleteAllContainers() 4961 4962 ctx, err := fakeContext(`FROM busybox 4963 RUN echo from Dockerfile`, 4964 map[string]string{ 4965 "Dockerfile": "FROM busybox\nRUN echo from Dockerfile", 4966 "files/Dockerfile": "FROM busybox\nRUN echo from files/Dockerfile", 4967 "files/dFile": "FROM busybox\nRUN echo from files/dFile", 4968 "dFile": "FROM busybox\nRUN echo from dFile", 4969 "files/dFile2": "FROM busybox\nRUN echo from files/dFile2", 4970 }) 4971 defer ctx.Close() 4972 if err != nil { 4973 t.Fatal(err) 4974 } 4975 4976 out, _, err := dockerCmdInDir(t, ctx.Dir, "build", "-t", "test1", ".") 4977 if err != nil { 4978 t.Fatalf("Failed to build: %s\n%s", out, err) 4979 } 4980 if !strings.Contains(out, "from Dockerfile") { 4981 t.Fatalf("test1 should have used Dockerfile, output:%s", out) 4982 } 4983 4984 out, _, err = dockerCmdInDir(t, ctx.Dir, "build", "-f", filepath.Join("files", "Dockerfile"), "-t", "test2", ".") 4985 if err != nil { 4986 t.Fatal(err) 4987 } 4988 if !strings.Contains(out, "from files/Dockerfile") { 4989 t.Fatalf("test2 should have used files/Dockerfile, output:%s", out) 4990 } 4991 4992 out, _, err = dockerCmdInDir(t, ctx.Dir, "build", fmt.Sprintf("--file=%s", filepath.Join("files", "dFile")), "-t", "test3", ".") 4993 if err != nil { 4994 t.Fatal(err) 4995 } 4996 if !strings.Contains(out, "from files/dFile") { 4997 t.Fatalf("test3 should have used files/dFile, output:%s", out) 4998 } 4999 5000 out, _, err = dockerCmdInDir(t, ctx.Dir, "build", "--file=dFile", "-t", "test4", ".") 5001 if err != nil { 5002 t.Fatal(err) 5003 } 5004 if !strings.Contains(out, "from dFile") { 5005 t.Fatalf("test4 should have used dFile, output:%s", out) 5006 } 5007 5008 dirWithNoDockerfile, _ := ioutil.TempDir(os.TempDir(), "test5") 5009 nonDockerfileFile := filepath.Join(dirWithNoDockerfile, "notDockerfile") 5010 if _, err = os.Create(nonDockerfileFile); err != nil { 5011 t.Fatal(err) 5012 } 5013 out, _, err = dockerCmdInDir(t, ctx.Dir, "build", fmt.Sprintf("--file=%s", nonDockerfileFile), "-t", "test5", ".") 5014 5015 if err == nil { 5016 t.Fatalf("test5 was supposed to fail to find passwd") 5017 } 5018 5019 if expected := fmt.Sprintf("The Dockerfile (%s) must be within the build context (.)", strings.Replace(nonDockerfileFile, `\`, `\\`, -1)); !strings.Contains(out, expected) { 5020 t.Fatalf("wrong error messsage:%v\nexpected to contain=%v", out, expected) 5021 } 5022 5023 out, _, err = dockerCmdInDir(t, filepath.Join(ctx.Dir, "files"), "build", "-f", filepath.Join("..", "Dockerfile"), "-t", "test6", "..") 5024 if err != nil { 5025 t.Fatalf("test6 failed: %s", err) 5026 } 5027 if !strings.Contains(out, "from Dockerfile") { 5028 t.Fatalf("test6 should have used root Dockerfile, output:%s", out) 5029 } 5030 5031 out, _, err = dockerCmdInDir(t, filepath.Join(ctx.Dir, "files"), "build", "-f", filepath.Join(ctx.Dir, "files", "Dockerfile"), "-t", "test7", "..") 5032 if err != nil { 5033 t.Fatalf("test7 failed: %s", err) 5034 } 5035 if !strings.Contains(out, "from files/Dockerfile") { 5036 t.Fatalf("test7 should have used files Dockerfile, output:%s", out) 5037 } 5038 5039 out, _, err = dockerCmdInDir(t, filepath.Join(ctx.Dir, "files"), "build", "-f", filepath.Join("..", "Dockerfile"), "-t", "test8", ".") 5040 if err == nil || !strings.Contains(out, "must be within the build context") { 5041 t.Fatalf("test8 should have failed with Dockerfile out of context: %s", err) 5042 } 5043 5044 tmpDir := os.TempDir() 5045 out, _, err = dockerCmdInDir(t, tmpDir, "build", "-t", "test9", ctx.Dir) 5046 if err != nil { 5047 t.Fatalf("test9 - failed: %s", err) 5048 } 5049 if !strings.Contains(out, "from Dockerfile") { 5050 t.Fatalf("test9 should have used root Dockerfile, output:%s", out) 5051 } 5052 5053 out, _, err = dockerCmdInDir(t, filepath.Join(ctx.Dir, "files"), "build", "-f", "dFile2", "-t", "test10", ".") 5054 if err != nil { 5055 t.Fatalf("test10 should have worked: %s", err) 5056 } 5057 if !strings.Contains(out, "from files/dFile2") { 5058 t.Fatalf("test10 should have used files/dFile2, output:%s", out) 5059 } 5060 5061 logDone("build - rename dockerfile") 5062 } 5063 5064 func TestBuildFromMixedcaseDockerfile(t *testing.T) { 5065 testRequires(t, UnixCli) // Dockerfile overwrites dockerfile on windows 5066 defer deleteImages("test1") 5067 5068 ctx, err := fakeContext(`FROM busybox 5069 RUN echo from dockerfile`, 5070 map[string]string{ 5071 "dockerfile": "FROM busybox\nRUN echo from dockerfile", 5072 }) 5073 defer ctx.Close() 5074 if err != nil { 5075 t.Fatal(err) 5076 } 5077 5078 out, _, err := dockerCmdInDir(t, ctx.Dir, "build", "-t", "test1", ".") 5079 if err != nil { 5080 t.Fatalf("Failed to build: %s\n%s", out, err) 5081 } 5082 5083 if !strings.Contains(out, "from dockerfile") { 5084 t.Fatalf("Missing proper output: %s", out) 5085 } 5086 5087 logDone("build - mixedcase Dockerfile") 5088 } 5089 5090 func TestBuildWithTwoDockerfiles(t *testing.T) { 5091 testRequires(t, UnixCli) // Dockerfile overwrites dockerfile on windows 5092 defer deleteImages("test1") 5093 5094 ctx, err := fakeContext(`FROM busybox 5095 RUN echo from Dockerfile`, 5096 map[string]string{ 5097 "dockerfile": "FROM busybox\nRUN echo from dockerfile", 5098 }) 5099 defer ctx.Close() 5100 if err != nil { 5101 t.Fatal(err) 5102 } 5103 5104 out, _, err := dockerCmdInDir(t, ctx.Dir, "build", "-t", "test1", ".") 5105 if err != nil { 5106 t.Fatalf("Failed to build: %s\n%s", out, err) 5107 } 5108 5109 if !strings.Contains(out, "from Dockerfile") { 5110 t.Fatalf("Missing proper output: %s", out) 5111 } 5112 5113 logDone("build - two Dockerfiles") 5114 } 5115 5116 func TestBuildFromURLWithF(t *testing.T) { 5117 defer deleteImages("test1") 5118 5119 server, err := fakeStorage(map[string]string{"baz": `FROM busybox 5120 RUN echo from baz 5121 COPY * /tmp/ 5122 RUN find /tmp/`}) 5123 if err != nil { 5124 t.Fatal(err) 5125 } 5126 defer server.Close() 5127 5128 ctx, err := fakeContext(`FROM busybox 5129 RUN echo from Dockerfile`, 5130 map[string]string{}) 5131 defer ctx.Close() 5132 if err != nil { 5133 t.Fatal(err) 5134 } 5135 5136 // Make sure that -f is ignored and that we don't use the Dockerfile 5137 // that's in the current dir 5138 out, _, err := dockerCmdInDir(t, ctx.Dir, "build", "-f", "baz", "-t", "test1", server.URL()+"/baz") 5139 if err != nil { 5140 t.Fatalf("Failed to build: %s\n%s", out, err) 5141 } 5142 5143 if !strings.Contains(out, "from baz") || 5144 strings.Contains(out, "/tmp/baz") || 5145 !strings.Contains(out, "/tmp/Dockerfile") { 5146 t.Fatalf("Missing proper output: %s", out) 5147 } 5148 5149 logDone("build - from URL with -f") 5150 } 5151 5152 func TestBuildFromStdinWithF(t *testing.T) { 5153 defer deleteImages("test1") 5154 5155 ctx, err := fakeContext(`FROM busybox 5156 RUN echo from Dockerfile`, 5157 map[string]string{}) 5158 defer ctx.Close() 5159 if err != nil { 5160 t.Fatal(err) 5161 } 5162 5163 // Make sure that -f is ignored and that we don't use the Dockerfile 5164 // that's in the current dir 5165 dockerCommand := exec.Command(dockerBinary, "build", "-f", "baz", "-t", "test1", "-") 5166 dockerCommand.Dir = ctx.Dir 5167 dockerCommand.Stdin = strings.NewReader(`FROM busybox 5168 RUN echo from baz 5169 COPY * /tmp/ 5170 RUN find /tmp/`) 5171 out, status, err := runCommandWithOutput(dockerCommand) 5172 if err != nil || status != 0 { 5173 t.Fatalf("Error building: %s", err) 5174 } 5175 5176 if !strings.Contains(out, "from baz") || 5177 strings.Contains(out, "/tmp/baz") || 5178 !strings.Contains(out, "/tmp/Dockerfile") { 5179 t.Fatalf("Missing proper output: %s", out) 5180 } 5181 5182 logDone("build - from stdin with -f") 5183 } 5184 5185 func TestBuildFromOfficialNames(t *testing.T) { 5186 name := "testbuildfromofficial" 5187 fromNames := []string{ 5188 "busybox", 5189 "docker.io/busybox", 5190 "index.docker.io/busybox", 5191 "library/busybox", 5192 "docker.io/library/busybox", 5193 "index.docker.io/library/busybox", 5194 } 5195 for idx, fromName := range fromNames { 5196 imgName := fmt.Sprintf("%s%d", name, idx) 5197 _, err := buildImage(imgName, "FROM "+fromName, true) 5198 if err != nil { 5199 t.Errorf("Build failed using FROM %s: %s", fromName, err) 5200 } 5201 deleteImages(imgName) 5202 } 5203 logDone("build - from official names") 5204 } 5205 5206 func TestBuildDockerfileOutsideContext(t *testing.T) { 5207 testRequires(t, UnixCli) // uses os.Symlink: not implemented in windows at the time of writing (go-1.4.2) 5208 5209 name := "testbuilddockerfileoutsidecontext" 5210 tmpdir, err := ioutil.TempDir("", name) 5211 if err != nil { 5212 t.Fatal(err) 5213 } 5214 defer os.RemoveAll(tmpdir) 5215 ctx := filepath.Join(tmpdir, "context") 5216 if err := os.MkdirAll(ctx, 0755); err != nil { 5217 t.Fatal(err) 5218 } 5219 if err := ioutil.WriteFile(filepath.Join(ctx, "Dockerfile"), []byte("FROM scratch\nENV X Y"), 0644); err != nil { 5220 t.Fatal(err) 5221 } 5222 wd, err := os.Getwd() 5223 if err != nil { 5224 t.Fatal(err) 5225 } 5226 defer os.Chdir(wd) 5227 if err := os.Chdir(ctx); err != nil { 5228 t.Fatal(err) 5229 } 5230 if err := ioutil.WriteFile(filepath.Join(tmpdir, "outsideDockerfile"), []byte("FROM scratch\nENV x y"), 0644); err != nil { 5231 t.Fatal(err) 5232 } 5233 if err := os.Symlink(filepath.Join("..", "outsideDockerfile"), filepath.Join(ctx, "dockerfile1")); err != nil { 5234 t.Fatal(err) 5235 } 5236 if err := os.Symlink(filepath.Join(tmpdir, "outsideDockerfile"), filepath.Join(ctx, "dockerfile2")); err != nil { 5237 t.Fatal(err) 5238 } 5239 5240 for _, dockerfilePath := range []string{ 5241 filepath.Join("..", "outsideDockerfile"), 5242 filepath.Join(ctx, "dockerfile1"), 5243 filepath.Join(ctx, "dockerfile2"), 5244 } { 5245 out, _, err := runCommandWithOutput(exec.Command(dockerBinary, "build", "-t", name, "--no-cache", "-f", dockerfilePath, ".")) 5246 if err == nil { 5247 t.Fatalf("Expected error with %s. Out: %s", dockerfilePath, out) 5248 } 5249 if !strings.Contains(out, "must be within the build context") && !strings.Contains(out, "Cannot locate Dockerfile") { 5250 t.Fatalf("Unexpected error with %s. Out: %s", dockerfilePath, out) 5251 } 5252 deleteImages(name) 5253 } 5254 5255 os.Chdir(tmpdir) 5256 5257 // Path to Dockerfile should be resolved relative to working directory, not relative to context. 5258 // There is a Dockerfile in the context, but since there is no Dockerfile in the current directory, the following should fail 5259 out, _, err := runCommandWithOutput(exec.Command(dockerBinary, "build", "-t", name, "--no-cache", "-f", "Dockerfile", ctx)) 5260 if err == nil { 5261 t.Fatalf("Expected error. Out: %s", out) 5262 } 5263 deleteImages(name) 5264 5265 logDone("build - Dockerfile outside context") 5266 } 5267 5268 func TestBuildSpaces(t *testing.T) { 5269 // Test to make sure that leading/trailing spaces on a command 5270 // doesn't change the error msg we get 5271 var ( 5272 err1 error 5273 err2 error 5274 ) 5275 5276 name := "testspaces" 5277 defer deleteImages(name) 5278 ctx, err := fakeContext("FROM busybox\nCOPY\n", 5279 map[string]string{ 5280 "Dockerfile": "FROM busybox\nCOPY\n", 5281 }) 5282 if err != nil { 5283 t.Fatal(err) 5284 } 5285 defer ctx.Close() 5286 5287 if _, err1 = buildImageFromContext(name, ctx, false); err1 == nil { 5288 t.Fatal("Build 1 was supposed to fail, but didn't") 5289 } 5290 5291 ctx.Add("Dockerfile", "FROM busybox\nCOPY ") 5292 if _, err2 = buildImageFromContext(name, ctx, false); err2 == nil { 5293 t.Fatal("Build 2 was supposed to fail, but didn't") 5294 } 5295 5296 removeLogTimestamps := func(s string) string { 5297 return regexp.MustCompile(`time="(.*?)"`).ReplaceAllString(s, `time=[TIMESTAMP]`) 5298 } 5299 5300 // Skip over the times 5301 e1 := removeLogTimestamps(err1.Error()) 5302 e2 := removeLogTimestamps(err2.Error()) 5303 5304 // Ignore whitespace since that's what were verifying doesn't change stuff 5305 if strings.Replace(e1, " ", "", -1) != strings.Replace(e2, " ", "", -1) { 5306 t.Fatalf("Build 2's error wasn't the same as build 1's\n1:%s\n2:%s", err1, err2) 5307 } 5308 5309 ctx.Add("Dockerfile", "FROM busybox\n COPY") 5310 if _, err2 = buildImageFromContext(name, ctx, false); err2 == nil { 5311 t.Fatal("Build 3 was supposed to fail, but didn't") 5312 } 5313 5314 // Skip over the times 5315 e1 = removeLogTimestamps(err1.Error()) 5316 e2 = removeLogTimestamps(err2.Error()) 5317 5318 // Ignore whitespace since that's what were verifying doesn't change stuff 5319 if strings.Replace(e1, " ", "", -1) != strings.Replace(e2, " ", "", -1) { 5320 t.Fatalf("Build 3's error wasn't the same as build 1's\n1:%s\n3:%s", err1, err2) 5321 } 5322 5323 ctx.Add("Dockerfile", "FROM busybox\n COPY ") 5324 if _, err2 = buildImageFromContext(name, ctx, false); err2 == nil { 5325 t.Fatal("Build 4 was supposed to fail, but didn't") 5326 } 5327 5328 // Skip over the times 5329 e1 = removeLogTimestamps(err1.Error()) 5330 e2 = removeLogTimestamps(err2.Error()) 5331 5332 // Ignore whitespace since that's what were verifying doesn't change stuff 5333 if strings.Replace(e1, " ", "", -1) != strings.Replace(e2, " ", "", -1) { 5334 t.Fatalf("Build 4's error wasn't the same as build 1's\n1:%s\n4:%s", err1, err2) 5335 } 5336 5337 logDone("build - test spaces") 5338 } 5339 5340 func TestBuildSpacesWithQuotes(t *testing.T) { 5341 // Test to make sure that spaces in quotes aren't lost 5342 name := "testspacesquotes" 5343 defer deleteImages(name) 5344 5345 dockerfile := `FROM busybox 5346 RUN echo " \ 5347 foo "` 5348 5349 _, out, err := buildImageWithOut(name, dockerfile, false) 5350 if err != nil { 5351 t.Fatal("Build failed:", err) 5352 } 5353 5354 expecting := "\n foo \n" 5355 if !strings.Contains(out, expecting) { 5356 t.Fatalf("Bad output: %q expecting to contian %q", out, expecting) 5357 } 5358 5359 logDone("build - test spaces with quotes") 5360 } 5361 5362 // #4393 5363 func TestBuildVolumeFileExistsinContainer(t *testing.T) { 5364 buildCmd := exec.Command(dockerBinary, "build", "-t", "docker-test-errcreatevolumewithfile", "-") 5365 buildCmd.Stdin = strings.NewReader(` 5366 FROM busybox 5367 RUN touch /foo 5368 VOLUME /foo 5369 `) 5370 5371 out, _, err := runCommandWithOutput(buildCmd) 5372 if err == nil || !strings.Contains(out, "file exists") { 5373 t.Fatalf("expected build to fail when file exists in container at requested volume path") 5374 } 5375 5376 logDone("build - errors when volume is specified where a file exists") 5377 } 5378 5379 func TestBuildMissingArgs(t *testing.T) { 5380 // Test to make sure that all Dockerfile commands (except the ones listed 5381 // in skipCmds) will generate an error if no args are provided. 5382 // Note: INSERT is deprecated so we exclude it because of that. 5383 skipCmds := map[string]struct{}{ 5384 "CMD": {}, 5385 "RUN": {}, 5386 "ENTRYPOINT": {}, 5387 "INSERT": {}, 5388 } 5389 5390 defer deleteAllContainers() 5391 5392 for cmd := range command.Commands { 5393 cmd = strings.ToUpper(cmd) 5394 if _, ok := skipCmds[cmd]; ok { 5395 continue 5396 } 5397 5398 var dockerfile string 5399 if cmd == "FROM" { 5400 dockerfile = cmd 5401 } else { 5402 // Add FROM to make sure we don't complain about it missing 5403 dockerfile = "FROM busybox\n" + cmd 5404 } 5405 5406 ctx, err := fakeContext(dockerfile, map[string]string{}) 5407 if err != nil { 5408 t.Fatal(err) 5409 } 5410 defer ctx.Close() 5411 var out string 5412 if out, err = buildImageFromContext("args", ctx, true); err == nil { 5413 t.Fatalf("%s was supposed to fail. Out:%s", cmd, out) 5414 } 5415 if !strings.Contains(err.Error(), cmd+" requires") { 5416 t.Fatalf("%s returned the wrong type of error:%s", cmd, err) 5417 } 5418 } 5419 5420 logDone("build - verify missing args") 5421 } 5422 5423 func TestBuildEmptyScratch(t *testing.T) { 5424 defer deleteImages("sc") 5425 _, out, err := buildImageWithOut("sc", "FROM scratch", true) 5426 if err == nil { 5427 t.Fatalf("Build was supposed to fail") 5428 } 5429 if !strings.Contains(out, "No image was generated") { 5430 t.Fatalf("Wrong error message: %v", out) 5431 } 5432 logDone("build - empty scratch Dockerfile") 5433 } 5434 5435 func TestBuildDotDotFile(t *testing.T) { 5436 defer deleteImages("sc") 5437 ctx, err := fakeContext("FROM busybox\n", 5438 map[string]string{ 5439 "..gitme": "", 5440 }) 5441 if err != nil { 5442 t.Fatal(err) 5443 } 5444 defer ctx.Close() 5445 5446 if _, err = buildImageFromContext("sc", ctx, false); err != nil { 5447 t.Fatalf("Build was supposed to work: %s", err) 5448 } 5449 logDone("build - ..file") 5450 } 5451 5452 func TestBuildNotVerbose(t *testing.T) { 5453 defer deleteAllContainers() 5454 defer deleteImages("verbose") 5455 5456 ctx, err := fakeContext("FROM busybox\nENV abc=hi\nRUN echo $abc there", map[string]string{}) 5457 if err != nil { 5458 t.Fatal(err) 5459 } 5460 defer ctx.Close() 5461 5462 // First do it w/verbose - baseline 5463 buildCmd := exec.Command(dockerBinary, "build", "--no-cache", "-t", "verbose", ".") 5464 buildCmd.Dir = ctx.Dir 5465 out, _, err := runCommandWithOutput(buildCmd) 5466 if err != nil { 5467 t.Fatalf("failed to build the image w/o -q: %s, %v", out, err) 5468 } 5469 if !strings.Contains(out, "hi there") { 5470 t.Fatalf("missing output:%s\n", out) 5471 } 5472 5473 // Now do it w/o verbose 5474 buildCmd = exec.Command(dockerBinary, "build", "--no-cache", "-q", "-t", "verbose", ".") 5475 buildCmd.Dir = ctx.Dir 5476 out, _, err = runCommandWithOutput(buildCmd) 5477 if err != nil { 5478 t.Fatalf("failed to build the image w/ -q: %s, %v", out, err) 5479 } 5480 if strings.Contains(out, "hi there") { 5481 t.Fatalf("Bad output, should not contain 'hi there':%s", out) 5482 } 5483 5484 logDone("build - not verbose") 5485 } 5486 5487 func TestBuildRUNoneJSON(t *testing.T) { 5488 name := "testbuildrunonejson" 5489 5490 defer deleteAllContainers() 5491 defer deleteImages(name) 5492 5493 ctx, err := fakeContext(`FROM hello-world:frozen 5494 RUN [ "/hello" ]`, map[string]string{}) 5495 if err != nil { 5496 t.Fatal(err) 5497 } 5498 defer ctx.Close() 5499 5500 buildCmd := exec.Command(dockerBinary, "build", "--no-cache", "-t", name, ".") 5501 buildCmd.Dir = ctx.Dir 5502 out, _, err := runCommandWithOutput(buildCmd) 5503 if err != nil { 5504 t.Fatalf("failed to build the image: %s, %v", out, err) 5505 } 5506 5507 if !strings.Contains(out, "Hello from Docker") { 5508 t.Fatalf("bad output: %s", out) 5509 } 5510 5511 logDone("build - RUN with one JSON arg") 5512 } 5513 5514 func TestBuildResourceConstraintsAreUsed(t *testing.T) { 5515 name := "testbuildresourceconstraints" 5516 defer deleteAllContainers() 5517 defer deleteImages(name) 5518 5519 ctx, err := fakeContext(` 5520 FROM hello-world:frozen 5521 RUN ["/hello"] 5522 `, map[string]string{}) 5523 if err != nil { 5524 t.Fatal(err) 5525 } 5526 5527 cmd := exec.Command(dockerBinary, "build", "--rm=false", "--memory=64m", "--memory-swap=-1", "--cpuset-cpus=1", "--cpu-shares=100", "-t", name, ".") 5528 cmd.Dir = ctx.Dir 5529 5530 out, _, err := runCommandWithOutput(cmd) 5531 if err != nil { 5532 t.Fatal(err, out) 5533 } 5534 out, _, err = dockerCmd(t, "ps", "-lq") 5535 if err != nil { 5536 t.Fatal(err, out) 5537 } 5538 5539 cID := stripTrailingCharacters(out) 5540 5541 type hostConfig struct { 5542 Memory float64 // Use float64 here since the json decoder sees it that way 5543 MemorySwap int 5544 CpusetCpus string 5545 CpuShares int 5546 } 5547 5548 cfg, err := inspectFieldJSON(cID, "HostConfig") 5549 if err != nil { 5550 t.Fatal(err) 5551 } 5552 5553 var c1 hostConfig 5554 if err := json.Unmarshal([]byte(cfg), &c1); err != nil { 5555 t.Fatal(err, cfg) 5556 } 5557 mem := int64(c1.Memory) 5558 if mem != 67108864 || c1.MemorySwap != -1 || c1.CpusetCpus != "1" || c1.CpuShares != 100 { 5559 t.Fatalf("resource constraints not set properly:\nMemory: %d, MemSwap: %d, CpusetCpus: %s, CpuShares: %d", 5560 mem, c1.MemorySwap, c1.CpusetCpus, c1.CpuShares) 5561 } 5562 5563 // Make sure constraints aren't saved to image 5564 _, _, err = dockerCmd(t, "run", "--name=test", name) 5565 if err != nil { 5566 t.Fatal(err) 5567 } 5568 cfg, err = inspectFieldJSON("test", "HostConfig") 5569 if err != nil { 5570 t.Fatal(err) 5571 } 5572 var c2 hostConfig 5573 if err := json.Unmarshal([]byte(cfg), &c2); err != nil { 5574 t.Fatal(err, cfg) 5575 } 5576 mem = int64(c2.Memory) 5577 if mem == 67108864 || c2.MemorySwap == -1 || c2.CpusetCpus == "1" || c2.CpuShares == 100 { 5578 t.Fatalf("resource constraints leaked from build:\nMemory: %d, MemSwap: %d, CpusetCpus: %s, CpuShares: %d", 5579 mem, c2.MemorySwap, c2.CpusetCpus, c2.CpuShares) 5580 } 5581 5582 logDone("build - resource constraints applied") 5583 } 5584 5585 func TestBuildEmptyStringVolume(t *testing.T) { 5586 name := "testbuildemptystringvolume" 5587 defer deleteImages(name) 5588 5589 _, err := buildImage(name, ` 5590 FROM busybox 5591 ENV foo="" 5592 VOLUME $foo 5593 `, false) 5594 if err == nil { 5595 t.Fatal("Should have failed to build") 5596 } 5597 5598 logDone("build - empty string volume") 5599 }