github.com/powellquiring/docker@v1.6.0-rc1/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 1962 // (Note: one year, will never finish) 1963 ctx, err := fakeContext("FROM busybox\nRUN sleep 31536000", nil) 1964 if err != nil { 1965 t.Fatal(err) 1966 } 1967 defer ctx.Close() 1968 1969 var wg sync.WaitGroup 1970 defer wg.Wait() 1971 1972 finish := make(chan struct{}) 1973 defer close(finish) 1974 1975 eventStart := make(chan struct{}) 1976 eventDie := make(chan struct{}) 1977 1978 // Start one second ago, to avoid rounding problems 1979 startEpoch := time.Now().Add(-1 * time.Second) 1980 1981 // Goroutine responsible for watching start/die events from `docker events` 1982 wg.Add(1) 1983 go func() { 1984 defer wg.Done() 1985 1986 // Watch for events since epoch. 1987 eventsCmd := exec.Command(dockerBinary, "events", 1988 "-since", fmt.Sprint(startEpoch.Unix())) 1989 stdout, err := eventsCmd.StdoutPipe() 1990 err = eventsCmd.Start() 1991 if err != nil { 1992 t.Fatalf("failed to start 'docker events': %s", err) 1993 } 1994 1995 go func() { 1996 <-finish 1997 eventsCmd.Process.Kill() 1998 }() 1999 2000 var started, died bool 2001 matchStart := regexp.MustCompile(" \\(from busybox\\:latest\\) start$") 2002 matchDie := regexp.MustCompile(" \\(from busybox\\:latest\\) die$") 2003 2004 // 2005 // Read lines of `docker events` looking for container start and stop. 2006 // 2007 scanner := bufio.NewScanner(stdout) 2008 for scanner.Scan() { 2009 if ok := matchStart.MatchString(scanner.Text()); ok { 2010 if started { 2011 t.Fatal("assertion fail: more than one container started") 2012 } 2013 close(eventStart) 2014 started = true 2015 } 2016 if ok := matchDie.MatchString(scanner.Text()); ok { 2017 if died { 2018 t.Fatal("assertion fail: more than one container died") 2019 } 2020 close(eventDie) 2021 died = true 2022 } 2023 } 2024 2025 err = eventsCmd.Wait() 2026 if err != nil && !IsKilled(err) { 2027 t.Fatalf("docker events had bad exit status: %s", err) 2028 } 2029 }() 2030 2031 buildCmd := exec.Command(dockerBinary, "build", "-t", name, ".") 2032 buildCmd.Dir = ctx.Dir 2033 buildCmd.Stdout = os.Stdout 2034 2035 err = buildCmd.Start() 2036 if err != nil { 2037 t.Fatalf("failed to run build: %s", err) 2038 } 2039 2040 select { 2041 case <-time.After(30 * time.Second): 2042 t.Fatal("failed to observe build container start in timely fashion") 2043 case <-eventStart: 2044 // Proceeds from here when we see the container fly past in the 2045 // output of "docker events". 2046 // Now we know the container is running. 2047 } 2048 2049 // Send a kill to the `docker build` command. 2050 // Causes the underlying build to be cancelled due to socket close. 2051 err = buildCmd.Process.Kill() 2052 if err != nil { 2053 t.Fatalf("error killing build command: %s", err) 2054 } 2055 2056 // Get the exit status of `docker build`, check it exited because killed. 2057 err = buildCmd.Wait() 2058 if err != nil && !IsKilled(err) { 2059 t.Fatalf("wait failed during build run: %T %s", err, err) 2060 } 2061 2062 select { 2063 case <-time.After(30 * time.Second): 2064 // If we don't get here in a timely fashion, it wasn't killed. 2065 t.Fatal("container cancel did not succeed") 2066 case <-eventDie: 2067 // We saw the container shut down in the `docker events` stream, 2068 // as expected. 2069 } 2070 2071 logDone("build - ensure canceled job finishes immediately") 2072 } 2073 2074 func TestBuildRm(t *testing.T) { 2075 name := "testbuildrm" 2076 defer deleteImages(name) 2077 ctx, err := fakeContext("FROM scratch\nADD foo /\nADD foo /", map[string]string{"foo": "bar"}) 2078 if err != nil { 2079 t.Fatal(err) 2080 } 2081 defer ctx.Close() 2082 { 2083 containerCountBefore, err := getContainerCount() 2084 if err != nil { 2085 t.Fatalf("failed to get the container count: %s", err) 2086 } 2087 2088 out, _, err := dockerCmdInDir(t, ctx.Dir, "build", "--rm", "-t", name, ".") 2089 2090 if err != nil { 2091 t.Fatal("failed to build the image", out) 2092 } 2093 2094 containerCountAfter, err := getContainerCount() 2095 if err != nil { 2096 t.Fatalf("failed to get the container count: %s", err) 2097 } 2098 2099 if containerCountBefore != containerCountAfter { 2100 t.Fatalf("-rm shouldn't have left containers behind") 2101 } 2102 deleteImages(name) 2103 } 2104 2105 { 2106 containerCountBefore, err := getContainerCount() 2107 if err != nil { 2108 t.Fatalf("failed to get the container count: %s", err) 2109 } 2110 2111 out, _, err := dockerCmdInDir(t, ctx.Dir, "build", "-t", name, ".") 2112 2113 if err != nil { 2114 t.Fatal("failed to build the image", out) 2115 } 2116 2117 containerCountAfter, err := getContainerCount() 2118 if err != nil { 2119 t.Fatalf("failed to get the container count: %s", err) 2120 } 2121 2122 if containerCountBefore != containerCountAfter { 2123 t.Fatalf("--rm shouldn't have left containers behind") 2124 } 2125 deleteImages(name) 2126 } 2127 2128 { 2129 containerCountBefore, err := getContainerCount() 2130 if err != nil { 2131 t.Fatalf("failed to get the container count: %s", err) 2132 } 2133 2134 out, _, err := dockerCmdInDir(t, ctx.Dir, "build", "--rm=false", "-t", name, ".") 2135 2136 if err != nil { 2137 t.Fatal("failed to build the image", out) 2138 } 2139 2140 containerCountAfter, err := getContainerCount() 2141 if err != nil { 2142 t.Fatalf("failed to get the container count: %s", err) 2143 } 2144 2145 if containerCountBefore == containerCountAfter { 2146 t.Fatalf("--rm=false should have left containers behind") 2147 } 2148 deleteAllContainers() 2149 deleteImages(name) 2150 2151 } 2152 2153 logDone("build - ensure --rm doesn't leave containers behind and that --rm=true is the default") 2154 logDone("build - ensure --rm=false overrides the default") 2155 } 2156 2157 func TestBuildWithVolumes(t *testing.T) { 2158 var ( 2159 result map[string]map[string]struct{} 2160 name = "testbuildvolumes" 2161 emptyMap = make(map[string]struct{}) 2162 expected = map[string]map[string]struct{}{ 2163 "/test1": emptyMap, 2164 "/test2": emptyMap, 2165 "/test3": emptyMap, 2166 "/test4": emptyMap, 2167 "/test5": emptyMap, 2168 "/test6": emptyMap, 2169 "[/test7": emptyMap, 2170 "/test8]": emptyMap, 2171 } 2172 ) 2173 defer deleteImages(name) 2174 _, err := buildImage(name, 2175 `FROM scratch 2176 VOLUME /test1 2177 VOLUME /test2 2178 VOLUME /test3 /test4 2179 VOLUME ["/test5", "/test6"] 2180 VOLUME [/test7 /test8] 2181 `, 2182 true) 2183 if err != nil { 2184 t.Fatal(err) 2185 } 2186 res, err := inspectFieldJSON(name, "Config.Volumes") 2187 if err != nil { 2188 t.Fatal(err) 2189 } 2190 2191 err = unmarshalJSON([]byte(res), &result) 2192 if err != nil { 2193 t.Fatal(err) 2194 } 2195 2196 equal := reflect.DeepEqual(&result, &expected) 2197 2198 if !equal { 2199 t.Fatalf("Volumes %s, expected %s", result, expected) 2200 } 2201 2202 logDone("build - with volumes") 2203 } 2204 2205 func TestBuildMaintainer(t *testing.T) { 2206 name := "testbuildmaintainer" 2207 expected := "dockerio" 2208 defer deleteImages(name) 2209 _, err := buildImage(name, 2210 `FROM scratch 2211 MAINTAINER dockerio`, 2212 true) 2213 if err != nil { 2214 t.Fatal(err) 2215 } 2216 res, err := inspectField(name, "Author") 2217 if err != nil { 2218 t.Fatal(err) 2219 } 2220 if res != expected { 2221 t.Fatalf("Maintainer %s, expected %s", res, expected) 2222 } 2223 logDone("build - maintainer") 2224 } 2225 2226 func TestBuildUser(t *testing.T) { 2227 name := "testbuilduser" 2228 expected := "dockerio" 2229 defer deleteImages(name) 2230 _, err := buildImage(name, 2231 `FROM busybox 2232 RUN echo 'dockerio:x:1001:1001::/bin:/bin/false' >> /etc/passwd 2233 USER dockerio 2234 RUN [ $(whoami) = 'dockerio' ]`, 2235 true) 2236 if err != nil { 2237 t.Fatal(err) 2238 } 2239 res, err := inspectField(name, "Config.User") 2240 if err != nil { 2241 t.Fatal(err) 2242 } 2243 if res != expected { 2244 t.Fatalf("User %s, expected %s", res, expected) 2245 } 2246 logDone("build - user") 2247 } 2248 2249 func TestBuildRelativeWorkdir(t *testing.T) { 2250 name := "testbuildrelativeworkdir" 2251 expected := "/test2/test3" 2252 defer deleteImages(name) 2253 _, err := buildImage(name, 2254 `FROM busybox 2255 RUN [ "$PWD" = '/' ] 2256 WORKDIR test1 2257 RUN [ "$PWD" = '/test1' ] 2258 WORKDIR /test2 2259 RUN [ "$PWD" = '/test2' ] 2260 WORKDIR test3 2261 RUN [ "$PWD" = '/test2/test3' ]`, 2262 true) 2263 if err != nil { 2264 t.Fatal(err) 2265 } 2266 res, err := inspectField(name, "Config.WorkingDir") 2267 if err != nil { 2268 t.Fatal(err) 2269 } 2270 if res != expected { 2271 t.Fatalf("Workdir %s, expected %s", res, expected) 2272 } 2273 logDone("build - relative workdir") 2274 } 2275 2276 func TestBuildWorkdirWithEnvVariables(t *testing.T) { 2277 name := "testbuildworkdirwithenvvariables" 2278 expected := "/test1/test2" 2279 defer deleteImages(name) 2280 _, err := buildImage(name, 2281 `FROM busybox 2282 ENV DIRPATH /test1 2283 ENV SUBDIRNAME test2 2284 WORKDIR $DIRPATH 2285 WORKDIR $SUBDIRNAME/$MISSING_VAR`, 2286 true) 2287 if err != nil { 2288 t.Fatal(err) 2289 } 2290 res, err := inspectField(name, "Config.WorkingDir") 2291 if err != nil { 2292 t.Fatal(err) 2293 } 2294 if res != expected { 2295 t.Fatalf("Workdir %s, expected %s", res, expected) 2296 } 2297 logDone("build - workdir with env variables") 2298 } 2299 2300 func TestBuildRelativeCopy(t *testing.T) { 2301 name := "testbuildrelativecopy" 2302 defer deleteImages(name) 2303 dockerfile := ` 2304 FROM busybox 2305 WORKDIR /test1 2306 WORKDIR test2 2307 RUN [ "$PWD" = '/test1/test2' ] 2308 COPY foo ./ 2309 RUN [ "$(cat /test1/test2/foo)" = 'hello' ] 2310 ADD foo ./bar/baz 2311 RUN [ "$(cat /test1/test2/bar/baz)" = 'hello' ] 2312 COPY foo ./bar/baz2 2313 RUN [ "$(cat /test1/test2/bar/baz2)" = 'hello' ] 2314 WORKDIR .. 2315 COPY foo ./ 2316 RUN [ "$(cat /test1/foo)" = 'hello' ] 2317 COPY foo /test3/ 2318 RUN [ "$(cat /test3/foo)" = 'hello' ] 2319 WORKDIR /test4 2320 COPY . . 2321 RUN [ "$(cat /test4/foo)" = 'hello' ] 2322 WORKDIR /test5/test6 2323 COPY foo ../ 2324 RUN [ "$(cat /test5/foo)" = 'hello' ] 2325 ` 2326 ctx, err := fakeContext(dockerfile, map[string]string{ 2327 "foo": "hello", 2328 }) 2329 defer ctx.Close() 2330 if err != nil { 2331 t.Fatal(err) 2332 } 2333 _, err = buildImageFromContext(name, ctx, false) 2334 if err != nil { 2335 t.Fatal(err) 2336 } 2337 logDone("build - relative copy/add") 2338 } 2339 2340 func TestBuildEnv(t *testing.T) { 2341 name := "testbuildenv" 2342 expected := "[PATH=/test:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin PORT=2375]" 2343 defer deleteImages(name) 2344 _, err := buildImage(name, 2345 `FROM busybox 2346 ENV PATH /test:$PATH 2347 ENV PORT 2375 2348 RUN [ $(env | grep PORT) = 'PORT=2375' ]`, 2349 true) 2350 if err != nil { 2351 t.Fatal(err) 2352 } 2353 res, err := inspectField(name, "Config.Env") 2354 if err != nil { 2355 t.Fatal(err) 2356 } 2357 if res != expected { 2358 t.Fatalf("Env %s, expected %s", res, expected) 2359 } 2360 logDone("build - env") 2361 } 2362 2363 func TestBuildContextCleanup(t *testing.T) { 2364 testRequires(t, SameHostDaemon) 2365 2366 name := "testbuildcontextcleanup" 2367 defer deleteImages(name) 2368 entries, err := ioutil.ReadDir("/var/lib/docker/tmp") 2369 if err != nil { 2370 t.Fatalf("failed to list contents of tmp dir: %s", err) 2371 } 2372 _, err = buildImage(name, 2373 `FROM scratch 2374 ENTRYPOINT ["/bin/echo"]`, 2375 true) 2376 if err != nil { 2377 t.Fatal(err) 2378 } 2379 entriesFinal, err := ioutil.ReadDir("/var/lib/docker/tmp") 2380 if err != nil { 2381 t.Fatalf("failed to list contents of tmp dir: %s", err) 2382 } 2383 if err = compareDirectoryEntries(entries, entriesFinal); err != nil { 2384 t.Fatalf("context should have been deleted, but wasn't") 2385 } 2386 2387 logDone("build - verify context cleanup works properly") 2388 } 2389 2390 func TestBuildContextCleanupFailedBuild(t *testing.T) { 2391 testRequires(t, SameHostDaemon) 2392 2393 name := "testbuildcontextcleanup" 2394 defer deleteImages(name) 2395 defer deleteAllContainers() 2396 entries, err := ioutil.ReadDir("/var/lib/docker/tmp") 2397 if err != nil { 2398 t.Fatalf("failed to list contents of tmp dir: %s", err) 2399 } 2400 _, err = buildImage(name, 2401 `FROM scratch 2402 RUN /non/existing/command`, 2403 true) 2404 if err == nil { 2405 t.Fatalf("expected build to fail, but it didn't") 2406 } 2407 entriesFinal, err := ioutil.ReadDir("/var/lib/docker/tmp") 2408 if err != nil { 2409 t.Fatalf("failed to list contents of tmp dir: %s", err) 2410 } 2411 if err = compareDirectoryEntries(entries, entriesFinal); err != nil { 2412 t.Fatalf("context should have been deleted, but wasn't") 2413 } 2414 2415 logDone("build - verify context cleanup works properly after an unsuccessful build") 2416 } 2417 2418 func TestBuildCmd(t *testing.T) { 2419 name := "testbuildcmd" 2420 expected := "[/bin/echo Hello World]" 2421 defer deleteImages(name) 2422 _, err := buildImage(name, 2423 `FROM scratch 2424 CMD ["/bin/echo", "Hello World"]`, 2425 true) 2426 if err != nil { 2427 t.Fatal(err) 2428 } 2429 res, err := inspectField(name, "Config.Cmd") 2430 if err != nil { 2431 t.Fatal(err) 2432 } 2433 if res != expected { 2434 t.Fatalf("Cmd %s, expected %s", res, expected) 2435 } 2436 logDone("build - cmd") 2437 } 2438 2439 func TestBuildExpose(t *testing.T) { 2440 name := "testbuildexpose" 2441 expected := "map[2375/tcp:map[]]" 2442 defer deleteImages(name) 2443 _, err := buildImage(name, 2444 `FROM scratch 2445 EXPOSE 2375`, 2446 true) 2447 if err != nil { 2448 t.Fatal(err) 2449 } 2450 res, err := inspectField(name, "Config.ExposedPorts") 2451 if err != nil { 2452 t.Fatal(err) 2453 } 2454 if res != expected { 2455 t.Fatalf("Exposed ports %s, expected %s", res, expected) 2456 } 2457 logDone("build - expose") 2458 } 2459 2460 func TestBuildExposeMorePorts(t *testing.T) { 2461 // start building docker file with a large number of ports 2462 portList := make([]string, 50) 2463 line := make([]string, 100) 2464 expectedPorts := make([]int, len(portList)*len(line)) 2465 for i := 0; i < len(portList); i++ { 2466 for j := 0; j < len(line); j++ { 2467 p := i*len(line) + j + 1 2468 line[j] = strconv.Itoa(p) 2469 expectedPorts[p-1] = p 2470 } 2471 if i == len(portList)-1 { 2472 portList[i] = strings.Join(line, " ") 2473 } else { 2474 portList[i] = strings.Join(line, " ") + ` \` 2475 } 2476 } 2477 2478 dockerfile := `FROM scratch 2479 EXPOSE {{range .}} {{.}} 2480 {{end}}` 2481 tmpl := template.Must(template.New("dockerfile").Parse(dockerfile)) 2482 buf := bytes.NewBuffer(nil) 2483 tmpl.Execute(buf, portList) 2484 2485 name := "testbuildexpose" 2486 defer deleteImages(name) 2487 _, err := buildImage(name, buf.String(), true) 2488 if err != nil { 2489 t.Fatal(err) 2490 } 2491 2492 // check if all the ports are saved inside Config.ExposedPorts 2493 res, err := inspectFieldJSON(name, "Config.ExposedPorts") 2494 if err != nil { 2495 t.Fatal(err) 2496 } 2497 var exposedPorts map[string]interface{} 2498 if err := json.Unmarshal([]byte(res), &exposedPorts); err != nil { 2499 t.Fatal(err) 2500 } 2501 2502 for _, p := range expectedPorts { 2503 ep := fmt.Sprintf("%d/tcp", p) 2504 if _, ok := exposedPorts[ep]; !ok { 2505 t.Errorf("Port(%s) is not exposed", ep) 2506 } else { 2507 delete(exposedPorts, ep) 2508 } 2509 } 2510 if len(exposedPorts) != 0 { 2511 t.Errorf("Unexpected extra exposed ports %v", exposedPorts) 2512 } 2513 logDone("build - expose large number of ports") 2514 } 2515 2516 func TestBuildExposeOrder(t *testing.T) { 2517 buildID := func(name, exposed string) string { 2518 _, err := buildImage(name, fmt.Sprintf(`FROM scratch 2519 EXPOSE %s`, exposed), true) 2520 if err != nil { 2521 t.Fatal(err) 2522 } 2523 id, err := inspectField(name, "Id") 2524 if err != nil { 2525 t.Fatal(err) 2526 } 2527 return id 2528 } 2529 2530 id1 := buildID("testbuildexpose1", "80 2375") 2531 id2 := buildID("testbuildexpose2", "2375 80") 2532 defer deleteImages("testbuildexpose1", "testbuildexpose2") 2533 if id1 != id2 { 2534 t.Errorf("EXPOSE should invalidate the cache only when ports actually changed") 2535 } 2536 logDone("build - expose order") 2537 } 2538 2539 func TestBuildExposeUpperCaseProto(t *testing.T) { 2540 name := "testbuildexposeuppercaseproto" 2541 expected := "map[5678/udp:map[]]" 2542 defer deleteImages(name) 2543 _, err := buildImage(name, 2544 `FROM scratch 2545 EXPOSE 5678/UDP`, 2546 true) 2547 if err != nil { 2548 t.Fatal(err) 2549 } 2550 res, err := inspectField(name, "Config.ExposedPorts") 2551 if err != nil { 2552 t.Fatal(err) 2553 } 2554 if res != expected { 2555 t.Fatalf("Exposed ports %s, expected %s", res, expected) 2556 } 2557 logDone("build - expose port with upper case proto") 2558 } 2559 2560 func TestBuildExposeHostPort(t *testing.T) { 2561 // start building docker file with ip:hostPort:containerPort 2562 name := "testbuildexpose" 2563 expected := "map[5678/tcp:map[]]" 2564 defer deleteImages(name) 2565 _, out, err := buildImageWithOut(name, 2566 `FROM scratch 2567 EXPOSE 192.168.1.2:2375:5678`, 2568 true) 2569 if err != nil { 2570 t.Fatal(err) 2571 } 2572 2573 if !strings.Contains(out, "to map host ports to container ports (ip:hostPort:containerPort) is deprecated.") { 2574 t.Fatal("Missing warning message") 2575 } 2576 2577 res, err := inspectField(name, "Config.ExposedPorts") 2578 if err != nil { 2579 t.Fatal(err) 2580 } 2581 if res != expected { 2582 t.Fatalf("Exposed ports %s, expected %s", res, expected) 2583 } 2584 logDone("build - ignore exposing host's port") 2585 } 2586 2587 func TestBuildEmptyEntrypointInheritance(t *testing.T) { 2588 name := "testbuildentrypointinheritance" 2589 name2 := "testbuildentrypointinheritance2" 2590 defer deleteImages(name, name2) 2591 2592 _, err := buildImage(name, 2593 `FROM busybox 2594 ENTRYPOINT ["/bin/echo"]`, 2595 true) 2596 if err != nil { 2597 t.Fatal(err) 2598 } 2599 res, err := inspectField(name, "Config.Entrypoint") 2600 if err != nil { 2601 t.Fatal(err) 2602 } 2603 2604 expected := "[/bin/echo]" 2605 if res != expected { 2606 t.Fatalf("Entrypoint %s, expected %s", res, expected) 2607 } 2608 2609 _, err = buildImage(name2, 2610 fmt.Sprintf(`FROM %s 2611 ENTRYPOINT []`, name), 2612 true) 2613 if err != nil { 2614 t.Fatal(err) 2615 } 2616 res, err = inspectField(name2, "Config.Entrypoint") 2617 if err != nil { 2618 t.Fatal(err) 2619 } 2620 2621 expected = "[]" 2622 2623 if res != expected { 2624 t.Fatalf("Entrypoint %s, expected %s", res, expected) 2625 } 2626 2627 logDone("build - empty entrypoint inheritance") 2628 } 2629 2630 func TestBuildEmptyEntrypoint(t *testing.T) { 2631 name := "testbuildentrypoint" 2632 defer deleteImages(name) 2633 expected := "[]" 2634 2635 _, err := buildImage(name, 2636 `FROM busybox 2637 ENTRYPOINT []`, 2638 true) 2639 if err != nil { 2640 t.Fatal(err) 2641 } 2642 res, err := inspectField(name, "Config.Entrypoint") 2643 if err != nil { 2644 t.Fatal(err) 2645 } 2646 if res != expected { 2647 t.Fatalf("Entrypoint %s, expected %s", res, expected) 2648 } 2649 2650 logDone("build - empty entrypoint") 2651 } 2652 2653 func TestBuildEntrypoint(t *testing.T) { 2654 name := "testbuildentrypoint" 2655 expected := "[/bin/echo]" 2656 defer deleteImages(name) 2657 _, err := buildImage(name, 2658 `FROM scratch 2659 ENTRYPOINT ["/bin/echo"]`, 2660 true) 2661 if err != nil { 2662 t.Fatal(err) 2663 } 2664 res, err := inspectField(name, "Config.Entrypoint") 2665 if err != nil { 2666 t.Fatal(err) 2667 } 2668 if res != expected { 2669 t.Fatalf("Entrypoint %s, expected %s", res, expected) 2670 } 2671 2672 logDone("build - entrypoint") 2673 } 2674 2675 // #6445 ensure ONBUILD triggers aren't committed to grandchildren 2676 func TestBuildOnBuildLimitedInheritence(t *testing.T) { 2677 var ( 2678 out2, out3 string 2679 ) 2680 { 2681 name1 := "testonbuildtrigger1" 2682 dockerfile1 := ` 2683 FROM busybox 2684 RUN echo "GRANDPARENT" 2685 ONBUILD RUN echo "ONBUILD PARENT" 2686 ` 2687 ctx, err := fakeContext(dockerfile1, nil) 2688 if err != nil { 2689 t.Fatal(err) 2690 } 2691 defer ctx.Close() 2692 2693 out1, _, err := dockerCmdInDir(t, ctx.Dir, "build", "-t", name1, ".") 2694 if err != nil { 2695 t.Fatalf("build failed to complete: %s, %v", out1, err) 2696 } 2697 defer deleteImages(name1) 2698 } 2699 { 2700 name2 := "testonbuildtrigger2" 2701 dockerfile2 := ` 2702 FROM testonbuildtrigger1 2703 ` 2704 ctx, err := fakeContext(dockerfile2, nil) 2705 if err != nil { 2706 t.Fatal(err) 2707 } 2708 defer ctx.Close() 2709 2710 out2, _, err = dockerCmdInDir(t, ctx.Dir, "build", "-t", name2, ".") 2711 if err != nil { 2712 t.Fatalf("build failed to complete: %s, %v", out2, err) 2713 } 2714 defer deleteImages(name2) 2715 } 2716 { 2717 name3 := "testonbuildtrigger3" 2718 dockerfile3 := ` 2719 FROM testonbuildtrigger2 2720 ` 2721 ctx, err := fakeContext(dockerfile3, nil) 2722 if err != nil { 2723 t.Fatal(err) 2724 } 2725 defer ctx.Close() 2726 2727 out3, _, err = dockerCmdInDir(t, ctx.Dir, "build", "-t", name3, ".") 2728 if err != nil { 2729 t.Fatalf("build failed to complete: %s, %v", out3, err) 2730 } 2731 2732 defer deleteImages(name3) 2733 } 2734 2735 // ONBUILD should be run in second build. 2736 if !strings.Contains(out2, "ONBUILD PARENT") { 2737 t.Fatalf("ONBUILD instruction did not run in child of ONBUILD parent") 2738 } 2739 2740 // ONBUILD should *not* be run in third build. 2741 if strings.Contains(out3, "ONBUILD PARENT") { 2742 t.Fatalf("ONBUILD instruction ran in grandchild of ONBUILD parent") 2743 } 2744 2745 logDone("build - onbuild") 2746 } 2747 2748 func TestBuildWithCache(t *testing.T) { 2749 name := "testbuildwithcache" 2750 defer deleteImages(name) 2751 id1, err := buildImage(name, 2752 `FROM scratch 2753 MAINTAINER dockerio 2754 EXPOSE 5432 2755 ENTRYPOINT ["/bin/echo"]`, 2756 true) 2757 if err != nil { 2758 t.Fatal(err) 2759 } 2760 id2, err := buildImage(name, 2761 `FROM scratch 2762 MAINTAINER dockerio 2763 EXPOSE 5432 2764 ENTRYPOINT ["/bin/echo"]`, 2765 true) 2766 if err != nil { 2767 t.Fatal(err) 2768 } 2769 if id1 != id2 { 2770 t.Fatal("The cache should have been used but hasn't.") 2771 } 2772 logDone("build - with cache") 2773 } 2774 2775 func TestBuildWithoutCache(t *testing.T) { 2776 name := "testbuildwithoutcache" 2777 name2 := "testbuildwithoutcache2" 2778 defer deleteImages(name, name2) 2779 id1, err := buildImage(name, 2780 `FROM scratch 2781 MAINTAINER dockerio 2782 EXPOSE 5432 2783 ENTRYPOINT ["/bin/echo"]`, 2784 true) 2785 if err != nil { 2786 t.Fatal(err) 2787 } 2788 2789 id2, err := buildImage(name2, 2790 `FROM scratch 2791 MAINTAINER dockerio 2792 EXPOSE 5432 2793 ENTRYPOINT ["/bin/echo"]`, 2794 false) 2795 if err != nil { 2796 t.Fatal(err) 2797 } 2798 if id1 == id2 { 2799 t.Fatal("The cache should have been invalided but hasn't.") 2800 } 2801 logDone("build - without cache") 2802 } 2803 2804 func TestBuildConditionalCache(t *testing.T) { 2805 name := "testbuildconditionalcache" 2806 name2 := "testbuildconditionalcache2" 2807 defer deleteImages(name, name2) 2808 2809 dockerfile := ` 2810 FROM busybox 2811 ADD foo /tmp/` 2812 ctx, err := fakeContext(dockerfile, map[string]string{ 2813 "foo": "hello", 2814 }) 2815 if err != nil { 2816 t.Fatal(err) 2817 } 2818 defer ctx.Close() 2819 2820 id1, err := buildImageFromContext(name, ctx, true) 2821 if err != nil { 2822 t.Fatalf("Error building #1: %s", err) 2823 } 2824 2825 if err := ctx.Add("foo", "bye"); err != nil { 2826 t.Fatalf("Error modifying foo: %s", err) 2827 } 2828 2829 id2, err := buildImageFromContext(name, ctx, false) 2830 if err != nil { 2831 t.Fatalf("Error building #2: %s", err) 2832 } 2833 if id2 == id1 { 2834 t.Fatal("Should not have used the cache") 2835 } 2836 2837 id3, err := buildImageFromContext(name, ctx, true) 2838 if err != nil { 2839 t.Fatalf("Error building #3: %s", err) 2840 } 2841 if id3 != id2 { 2842 t.Fatal("Should have used the cache") 2843 } 2844 2845 logDone("build - conditional cache") 2846 } 2847 2848 func TestBuildADDLocalFileWithCache(t *testing.T) { 2849 name := "testbuildaddlocalfilewithcache" 2850 name2 := "testbuildaddlocalfilewithcache2" 2851 defer deleteImages(name, name2) 2852 dockerfile := ` 2853 FROM busybox 2854 MAINTAINER dockerio 2855 ADD foo /usr/lib/bla/bar 2856 RUN [ "$(cat /usr/lib/bla/bar)" = "hello" ]` 2857 ctx, err := fakeContext(dockerfile, map[string]string{ 2858 "foo": "hello", 2859 }) 2860 defer ctx.Close() 2861 if err != nil { 2862 t.Fatal(err) 2863 } 2864 id1, err := buildImageFromContext(name, ctx, true) 2865 if err != nil { 2866 t.Fatal(err) 2867 } 2868 id2, err := buildImageFromContext(name2, ctx, true) 2869 if err != nil { 2870 t.Fatal(err) 2871 } 2872 if id1 != id2 { 2873 t.Fatal("The cache should have been used but hasn't.") 2874 } 2875 logDone("build - add local file with cache") 2876 } 2877 2878 func TestBuildADDMultipleLocalFileWithCache(t *testing.T) { 2879 name := "testbuildaddmultiplelocalfilewithcache" 2880 name2 := "testbuildaddmultiplelocalfilewithcache2" 2881 defer deleteImages(name, name2) 2882 dockerfile := ` 2883 FROM busybox 2884 MAINTAINER dockerio 2885 ADD foo Dockerfile /usr/lib/bla/ 2886 RUN [ "$(cat /usr/lib/bla/foo)" = "hello" ]` 2887 ctx, err := fakeContext(dockerfile, map[string]string{ 2888 "foo": "hello", 2889 }) 2890 defer ctx.Close() 2891 if err != nil { 2892 t.Fatal(err) 2893 } 2894 id1, err := buildImageFromContext(name, ctx, true) 2895 if err != nil { 2896 t.Fatal(err) 2897 } 2898 id2, err := buildImageFromContext(name2, ctx, true) 2899 if err != nil { 2900 t.Fatal(err) 2901 } 2902 if id1 != id2 { 2903 t.Fatal("The cache should have been used but hasn't.") 2904 } 2905 logDone("build - add multiple local files with cache") 2906 } 2907 2908 func TestBuildADDLocalFileWithoutCache(t *testing.T) { 2909 name := "testbuildaddlocalfilewithoutcache" 2910 name2 := "testbuildaddlocalfilewithoutcache2" 2911 defer deleteImages(name, name2) 2912 dockerfile := ` 2913 FROM busybox 2914 MAINTAINER dockerio 2915 ADD foo /usr/lib/bla/bar 2916 RUN [ "$(cat /usr/lib/bla/bar)" = "hello" ]` 2917 ctx, err := fakeContext(dockerfile, map[string]string{ 2918 "foo": "hello", 2919 }) 2920 defer ctx.Close() 2921 if err != nil { 2922 t.Fatal(err) 2923 } 2924 id1, err := buildImageFromContext(name, ctx, true) 2925 if err != nil { 2926 t.Fatal(err) 2927 } 2928 id2, err := buildImageFromContext(name2, ctx, false) 2929 if err != nil { 2930 t.Fatal(err) 2931 } 2932 if id1 == id2 { 2933 t.Fatal("The cache should have been invalided but hasn't.") 2934 } 2935 logDone("build - add local file without cache") 2936 } 2937 2938 func TestBuildCopyDirButNotFile(t *testing.T) { 2939 name := "testbuildcopydirbutnotfile" 2940 name2 := "testbuildcopydirbutnotfile2" 2941 defer deleteImages(name, name2) 2942 dockerfile := ` 2943 FROM scratch 2944 COPY dir /tmp/` 2945 ctx, err := fakeContext(dockerfile, map[string]string{ 2946 "dir/foo": "hello", 2947 }) 2948 defer ctx.Close() 2949 if err != nil { 2950 t.Fatal(err) 2951 } 2952 id1, err := buildImageFromContext(name, ctx, true) 2953 if err != nil { 2954 t.Fatal(err) 2955 } 2956 // Check that adding file with similar name doesn't mess with cache 2957 if err := ctx.Add("dir_file", "hello2"); err != nil { 2958 t.Fatal(err) 2959 } 2960 id2, err := buildImageFromContext(name2, ctx, true) 2961 if err != nil { 2962 t.Fatal(err) 2963 } 2964 if id1 != id2 { 2965 t.Fatal("The cache should have been used but wasn't") 2966 } 2967 logDone("build - add current directory but not file") 2968 } 2969 2970 func TestBuildADDCurrentDirWithCache(t *testing.T) { 2971 name := "testbuildaddcurrentdirwithcache" 2972 name2 := name + "2" 2973 name3 := name + "3" 2974 name4 := name + "4" 2975 name5 := name + "5" 2976 defer deleteImages(name, name2, name3, name4, name5) 2977 dockerfile := ` 2978 FROM scratch 2979 MAINTAINER dockerio 2980 ADD . /usr/lib/bla` 2981 ctx, err := fakeContext(dockerfile, map[string]string{ 2982 "foo": "hello", 2983 }) 2984 defer ctx.Close() 2985 if err != nil { 2986 t.Fatal(err) 2987 } 2988 id1, err := buildImageFromContext(name, ctx, true) 2989 if err != nil { 2990 t.Fatal(err) 2991 } 2992 // Check that adding file invalidate cache of "ADD ." 2993 if err := ctx.Add("bar", "hello2"); err != nil { 2994 t.Fatal(err) 2995 } 2996 id2, err := buildImageFromContext(name2, ctx, true) 2997 if err != nil { 2998 t.Fatal(err) 2999 } 3000 if id1 == id2 { 3001 t.Fatal("The cache should have been invalided but hasn't.") 3002 } 3003 // Check that changing file invalidate cache of "ADD ." 3004 if err := ctx.Add("foo", "hello1"); err != nil { 3005 t.Fatal(err) 3006 } 3007 id3, err := buildImageFromContext(name3, ctx, true) 3008 if err != nil { 3009 t.Fatal(err) 3010 } 3011 if id2 == id3 { 3012 t.Fatal("The cache should have been invalided but hasn't.") 3013 } 3014 // Check that changing file to same content invalidate cache of "ADD ." 3015 time.Sleep(1 * time.Second) // wait second because of mtime precision 3016 if err := ctx.Add("foo", "hello1"); err != nil { 3017 t.Fatal(err) 3018 } 3019 id4, err := buildImageFromContext(name4, ctx, true) 3020 if err != nil { 3021 t.Fatal(err) 3022 } 3023 if id3 == id4 { 3024 t.Fatal("The cache should have been invalided but hasn't.") 3025 } 3026 id5, err := buildImageFromContext(name5, ctx, true) 3027 if err != nil { 3028 t.Fatal(err) 3029 } 3030 if id4 != id5 { 3031 t.Fatal("The cache should have been used but hasn't.") 3032 } 3033 logDone("build - add current directory with cache") 3034 } 3035 3036 func TestBuildADDCurrentDirWithoutCache(t *testing.T) { 3037 name := "testbuildaddcurrentdirwithoutcache" 3038 name2 := "testbuildaddcurrentdirwithoutcache2" 3039 defer deleteImages(name, name2) 3040 dockerfile := ` 3041 FROM scratch 3042 MAINTAINER dockerio 3043 ADD . /usr/lib/bla` 3044 ctx, err := fakeContext(dockerfile, map[string]string{ 3045 "foo": "hello", 3046 }) 3047 defer ctx.Close() 3048 if err != nil { 3049 t.Fatal(err) 3050 } 3051 id1, err := buildImageFromContext(name, ctx, true) 3052 if err != nil { 3053 t.Fatal(err) 3054 } 3055 id2, err := buildImageFromContext(name2, ctx, false) 3056 if err != nil { 3057 t.Fatal(err) 3058 } 3059 if id1 == id2 { 3060 t.Fatal("The cache should have been invalided but hasn't.") 3061 } 3062 logDone("build - add current directory without cache") 3063 } 3064 3065 func TestBuildADDRemoteFileWithCache(t *testing.T) { 3066 name := "testbuildaddremotefilewithcache" 3067 defer deleteImages(name) 3068 server, err := fakeStorage(map[string]string{ 3069 "baz": "hello", 3070 }) 3071 if err != nil { 3072 t.Fatal(err) 3073 } 3074 defer server.Close() 3075 3076 id1, err := buildImage(name, 3077 fmt.Sprintf(`FROM scratch 3078 MAINTAINER dockerio 3079 ADD %s/baz /usr/lib/baz/quux`, server.URL()), 3080 true) 3081 if err != nil { 3082 t.Fatal(err) 3083 } 3084 id2, err := buildImage(name, 3085 fmt.Sprintf(`FROM scratch 3086 MAINTAINER dockerio 3087 ADD %s/baz /usr/lib/baz/quux`, server.URL()), 3088 true) 3089 if err != nil { 3090 t.Fatal(err) 3091 } 3092 if id1 != id2 { 3093 t.Fatal("The cache should have been used but hasn't.") 3094 } 3095 logDone("build - add remote file with cache") 3096 } 3097 3098 func TestBuildADDRemoteFileWithoutCache(t *testing.T) { 3099 name := "testbuildaddremotefilewithoutcache" 3100 name2 := "testbuildaddremotefilewithoutcache2" 3101 defer deleteImages(name, name2) 3102 server, err := fakeStorage(map[string]string{ 3103 "baz": "hello", 3104 }) 3105 if err != nil { 3106 t.Fatal(err) 3107 } 3108 defer server.Close() 3109 3110 id1, err := buildImage(name, 3111 fmt.Sprintf(`FROM scratch 3112 MAINTAINER dockerio 3113 ADD %s/baz /usr/lib/baz/quux`, server.URL()), 3114 true) 3115 if err != nil { 3116 t.Fatal(err) 3117 } 3118 id2, err := buildImage(name2, 3119 fmt.Sprintf(`FROM scratch 3120 MAINTAINER dockerio 3121 ADD %s/baz /usr/lib/baz/quux`, server.URL()), 3122 false) 3123 if err != nil { 3124 t.Fatal(err) 3125 } 3126 if id1 == id2 { 3127 t.Fatal("The cache should have been invalided but hasn't.") 3128 } 3129 logDone("build - add remote file without cache") 3130 } 3131 3132 func TestBuildADDRemoteFileMTime(t *testing.T) { 3133 name := "testbuildaddremotefilemtime" 3134 name2 := name + "2" 3135 name3 := name + "3" 3136 name4 := name + "4" 3137 3138 defer deleteImages(name, name2, name3, name4) 3139 3140 files := map[string]string{"baz": "hello"} 3141 server, err := fakeStorage(files) 3142 if err != nil { 3143 t.Fatal(err) 3144 } 3145 defer server.Close() 3146 3147 ctx, err := fakeContext(fmt.Sprintf(`FROM scratch 3148 MAINTAINER dockerio 3149 ADD %s/baz /usr/lib/baz/quux`, server.URL()), nil) 3150 if err != nil { 3151 t.Fatal(err) 3152 } 3153 defer ctx.Close() 3154 3155 id1, err := buildImageFromContext(name, ctx, true) 3156 if err != nil { 3157 t.Fatal(err) 3158 } 3159 3160 id2, err := buildImageFromContext(name2, ctx, true) 3161 if err != nil { 3162 t.Fatal(err) 3163 } 3164 if id1 != id2 { 3165 t.Fatal("The cache should have been used but wasn't - #1") 3166 } 3167 3168 // Now create a different server withsame contents (causes different mtim) 3169 // This time the cache should not be used 3170 3171 // allow some time for clock to pass as mtime precision is only 1s 3172 time.Sleep(2 * time.Second) 3173 3174 server2, err := fakeStorage(files) 3175 if err != nil { 3176 t.Fatal(err) 3177 } 3178 defer server2.Close() 3179 3180 ctx2, err := fakeContext(fmt.Sprintf(`FROM scratch 3181 MAINTAINER dockerio 3182 ADD %s/baz /usr/lib/baz/quux`, server2.URL()), nil) 3183 if err != nil { 3184 t.Fatal(err) 3185 } 3186 defer ctx2.Close() 3187 id3, err := buildImageFromContext(name3, ctx2, true) 3188 if err != nil { 3189 t.Fatal(err) 3190 } 3191 if id1 == id3 { 3192 t.Fatal("The cache should not have been used but was") 3193 } 3194 3195 // And for good measure do it again and make sure cache is used this time 3196 id4, err := buildImageFromContext(name4, ctx2, true) 3197 if err != nil { 3198 t.Fatal(err) 3199 } 3200 if id3 != id4 { 3201 t.Fatal("The cache should have been used but wasn't - #2") 3202 } 3203 logDone("build - add remote file testing mtime") 3204 } 3205 3206 func TestBuildADDLocalAndRemoteFilesWithCache(t *testing.T) { 3207 name := "testbuildaddlocalandremotefilewithcache" 3208 defer deleteImages(name) 3209 server, err := fakeStorage(map[string]string{ 3210 "baz": "hello", 3211 }) 3212 if err != nil { 3213 t.Fatal(err) 3214 } 3215 defer server.Close() 3216 3217 ctx, err := fakeContext(fmt.Sprintf(`FROM scratch 3218 MAINTAINER dockerio 3219 ADD foo /usr/lib/bla/bar 3220 ADD %s/baz /usr/lib/baz/quux`, server.URL()), 3221 map[string]string{ 3222 "foo": "hello world", 3223 }) 3224 if err != nil { 3225 t.Fatal(err) 3226 } 3227 defer ctx.Close() 3228 id1, err := buildImageFromContext(name, ctx, true) 3229 if err != nil { 3230 t.Fatal(err) 3231 } 3232 id2, err := buildImageFromContext(name, ctx, true) 3233 if err != nil { 3234 t.Fatal(err) 3235 } 3236 if id1 != id2 { 3237 t.Fatal("The cache should have been used but hasn't.") 3238 } 3239 logDone("build - add local and remote file with cache") 3240 } 3241 3242 func testContextTar(t *testing.T, compression archive.Compression) { 3243 ctx, err := fakeContext( 3244 `FROM busybox 3245 ADD foo /foo 3246 CMD ["cat", "/foo"]`, 3247 map[string]string{ 3248 "foo": "bar", 3249 }, 3250 ) 3251 defer ctx.Close() 3252 if err != nil { 3253 t.Fatal(err) 3254 } 3255 context, err := archive.Tar(ctx.Dir, compression) 3256 if err != nil { 3257 t.Fatalf("failed to build context tar: %v", err) 3258 } 3259 name := "contexttar" 3260 buildCmd := exec.Command(dockerBinary, "build", "-t", name, "-") 3261 defer deleteImages(name) 3262 buildCmd.Stdin = context 3263 3264 if out, _, err := runCommandWithOutput(buildCmd); err != nil { 3265 t.Fatalf("build failed to complete: %v %v", out, err) 3266 } 3267 logDone(fmt.Sprintf("build - build an image with a context tar, compression: %v", compression)) 3268 } 3269 3270 func TestBuildContextTarGzip(t *testing.T) { 3271 testContextTar(t, archive.Gzip) 3272 } 3273 3274 func TestBuildContextTarNoCompression(t *testing.T) { 3275 testContextTar(t, archive.Uncompressed) 3276 } 3277 3278 func TestBuildNoContext(t *testing.T) { 3279 buildCmd := exec.Command(dockerBinary, "build", "-t", "nocontext", "-") 3280 buildCmd.Stdin = strings.NewReader("FROM busybox\nCMD echo ok\n") 3281 3282 if out, _, err := runCommandWithOutput(buildCmd); err != nil { 3283 t.Fatalf("build failed to complete: %v %v", out, err) 3284 } 3285 3286 if out, _, err := dockerCmd(t, "run", "--rm", "nocontext"); out != "ok\n" || err != nil { 3287 t.Fatalf("run produced invalid output: %q, expected %q", out, "ok") 3288 } 3289 3290 deleteImages("nocontext") 3291 logDone("build - build an image with no context") 3292 } 3293 3294 // TODO: TestCaching 3295 func TestBuildADDLocalAndRemoteFilesWithoutCache(t *testing.T) { 3296 name := "testbuildaddlocalandremotefilewithoutcache" 3297 name2 := "testbuildaddlocalandremotefilewithoutcache2" 3298 defer deleteImages(name, name2) 3299 server, err := fakeStorage(map[string]string{ 3300 "baz": "hello", 3301 }) 3302 if err != nil { 3303 t.Fatal(err) 3304 } 3305 defer server.Close() 3306 3307 ctx, err := fakeContext(fmt.Sprintf(`FROM scratch 3308 MAINTAINER dockerio 3309 ADD foo /usr/lib/bla/bar 3310 ADD %s/baz /usr/lib/baz/quux`, server.URL()), 3311 map[string]string{ 3312 "foo": "hello world", 3313 }) 3314 if err != nil { 3315 t.Fatal(err) 3316 } 3317 defer ctx.Close() 3318 id1, err := buildImageFromContext(name, ctx, true) 3319 if err != nil { 3320 t.Fatal(err) 3321 } 3322 id2, err := buildImageFromContext(name2, ctx, false) 3323 if err != nil { 3324 t.Fatal(err) 3325 } 3326 if id1 == id2 { 3327 t.Fatal("The cache should have been invalided but hasn't.") 3328 } 3329 logDone("build - add local and remote file without cache") 3330 } 3331 3332 func TestBuildWithVolumeOwnership(t *testing.T) { 3333 name := "testbuildimg" 3334 defer deleteImages(name) 3335 3336 _, err := buildImage(name, 3337 `FROM busybox:latest 3338 RUN mkdir /test && chown daemon:daemon /test && chmod 0600 /test 3339 VOLUME /test`, 3340 true) 3341 3342 if err != nil { 3343 t.Fatal(err) 3344 } 3345 3346 cmd := exec.Command(dockerBinary, "run", "--rm", "testbuildimg", "ls", "-la", "/test") 3347 out, _, err := runCommandWithOutput(cmd) 3348 if err != nil { 3349 t.Fatal(out, err) 3350 } 3351 3352 if expected := "drw-------"; !strings.Contains(out, expected) { 3353 t.Fatalf("expected %s received %s", expected, out) 3354 } 3355 3356 if expected := "daemon daemon"; !strings.Contains(out, expected) { 3357 t.Fatalf("expected %s received %s", expected, out) 3358 } 3359 3360 logDone("build - volume ownership") 3361 } 3362 3363 // testing #1405 - config.Cmd does not get cleaned up if 3364 // utilizing cache 3365 func TestBuildEntrypointRunCleanup(t *testing.T) { 3366 name := "testbuildcmdcleanup" 3367 defer deleteImages(name) 3368 if _, err := buildImage(name, 3369 `FROM busybox 3370 RUN echo "hello"`, 3371 true); err != nil { 3372 t.Fatal(err) 3373 } 3374 3375 ctx, err := fakeContext(`FROM busybox 3376 RUN echo "hello" 3377 ADD foo /foo 3378 ENTRYPOINT ["/bin/echo"]`, 3379 map[string]string{ 3380 "foo": "hello", 3381 }) 3382 defer ctx.Close() 3383 if err != nil { 3384 t.Fatal(err) 3385 } 3386 if _, err := buildImageFromContext(name, ctx, true); err != nil { 3387 t.Fatal(err) 3388 } 3389 res, err := inspectField(name, "Config.Cmd") 3390 if err != nil { 3391 t.Fatal(err) 3392 } 3393 // Cmd must be cleaned up 3394 if expected := "<no value>"; res != expected { 3395 t.Fatalf("Cmd %s, expected %s", res, expected) 3396 } 3397 logDone("build - cleanup cmd after RUN") 3398 } 3399 3400 func TestBuildForbiddenContextPath(t *testing.T) { 3401 name := "testbuildforbidpath" 3402 defer deleteImages(name) 3403 ctx, err := fakeContext(`FROM scratch 3404 ADD ../../ test/ 3405 `, 3406 map[string]string{ 3407 "test.txt": "test1", 3408 "other.txt": "other", 3409 }) 3410 defer ctx.Close() 3411 if err != nil { 3412 t.Fatal(err) 3413 } 3414 3415 expected := "Forbidden path outside the build context: ../../ " 3416 if _, err := buildImageFromContext(name, ctx, true); err == nil || !strings.Contains(err.Error(), expected) { 3417 t.Fatalf("Wrong error: (should contain \"%s\") got:\n%v", expected, err) 3418 } 3419 3420 logDone("build - forbidden context path") 3421 } 3422 3423 func TestBuildADDFileNotFound(t *testing.T) { 3424 name := "testbuildaddnotfound" 3425 defer deleteImages(name) 3426 ctx, err := fakeContext(`FROM scratch 3427 ADD foo /usr/local/bar`, 3428 map[string]string{"bar": "hello"}) 3429 defer ctx.Close() 3430 if err != nil { 3431 t.Fatal(err) 3432 } 3433 if _, err := buildImageFromContext(name, ctx, true); err != nil { 3434 if !strings.Contains(err.Error(), "foo: no such file or directory") { 3435 t.Fatalf("Wrong error %v, must be about missing foo file or directory", err) 3436 } 3437 } else { 3438 t.Fatal("Error must not be nil") 3439 } 3440 logDone("build - add file not found") 3441 } 3442 3443 func TestBuildInheritance(t *testing.T) { 3444 name := "testbuildinheritance" 3445 defer deleteImages(name) 3446 3447 _, err := buildImage(name, 3448 `FROM scratch 3449 EXPOSE 2375`, 3450 true) 3451 if err != nil { 3452 t.Fatal(err) 3453 } 3454 ports1, err := inspectField(name, "Config.ExposedPorts") 3455 if err != nil { 3456 t.Fatal(err) 3457 } 3458 3459 _, err = buildImage(name, 3460 fmt.Sprintf(`FROM %s 3461 ENTRYPOINT ["/bin/echo"]`, name), 3462 true) 3463 if err != nil { 3464 t.Fatal(err) 3465 } 3466 3467 res, err := inspectField(name, "Config.Entrypoint") 3468 if err != nil { 3469 t.Fatal(err) 3470 } 3471 if expected := "[/bin/echo]"; res != expected { 3472 t.Fatalf("Entrypoint %s, expected %s", res, expected) 3473 } 3474 ports2, err := inspectField(name, "Config.ExposedPorts") 3475 if err != nil { 3476 t.Fatal(err) 3477 } 3478 if ports1 != ports2 { 3479 t.Fatalf("Ports must be same: %s != %s", ports1, ports2) 3480 } 3481 logDone("build - inheritance") 3482 } 3483 3484 func TestBuildFails(t *testing.T) { 3485 name := "testbuildfails" 3486 defer deleteImages(name) 3487 defer deleteAllContainers() 3488 _, err := buildImage(name, 3489 `FROM busybox 3490 RUN sh -c "exit 23"`, 3491 true) 3492 if err != nil { 3493 if !strings.Contains(err.Error(), "returned a non-zero code: 23") { 3494 t.Fatalf("Wrong error %v, must be about non-zero code 23", err) 3495 } 3496 } else { 3497 t.Fatal("Error must not be nil") 3498 } 3499 logDone("build - unsuccessful") 3500 } 3501 3502 func TestBuildFailsDockerfileEmpty(t *testing.T) { 3503 name := "testbuildfails" 3504 defer deleteImages(name) 3505 _, err := buildImage(name, ``, true) 3506 if err != nil { 3507 if !strings.Contains(err.Error(), "Dockerfile cannot be empty") { 3508 t.Fatalf("Wrong error %v, must be about empty Dockerfile", err) 3509 } 3510 } else { 3511 t.Fatal("Error must not be nil") 3512 } 3513 logDone("build - unsuccessful with empty dockerfile") 3514 } 3515 3516 func TestBuildOnBuild(t *testing.T) { 3517 name := "testbuildonbuild" 3518 defer deleteImages(name) 3519 _, err := buildImage(name, 3520 `FROM busybox 3521 ONBUILD RUN touch foobar`, 3522 true) 3523 if err != nil { 3524 t.Fatal(err) 3525 } 3526 _, err = buildImage(name, 3527 fmt.Sprintf(`FROM %s 3528 RUN [ -f foobar ]`, name), 3529 true) 3530 if err != nil { 3531 t.Fatal(err) 3532 } 3533 logDone("build - onbuild") 3534 } 3535 3536 func TestBuildOnBuildForbiddenChained(t *testing.T) { 3537 name := "testbuildonbuildforbiddenchained" 3538 defer deleteImages(name) 3539 _, err := buildImage(name, 3540 `FROM busybox 3541 ONBUILD ONBUILD RUN touch foobar`, 3542 true) 3543 if err != nil { 3544 if !strings.Contains(err.Error(), "Chaining ONBUILD via `ONBUILD ONBUILD` isn't allowed") { 3545 t.Fatalf("Wrong error %v, must be about chaining ONBUILD", err) 3546 } 3547 } else { 3548 t.Fatal("Error must not be nil") 3549 } 3550 logDone("build - onbuild forbidden chained") 3551 } 3552 3553 func TestBuildOnBuildForbiddenFrom(t *testing.T) { 3554 name := "testbuildonbuildforbiddenfrom" 3555 defer deleteImages(name) 3556 _, err := buildImage(name, 3557 `FROM busybox 3558 ONBUILD FROM scratch`, 3559 true) 3560 if err != nil { 3561 if !strings.Contains(err.Error(), "FROM isn't allowed as an ONBUILD trigger") { 3562 t.Fatalf("Wrong error %v, must be about FROM forbidden", err) 3563 } 3564 } else { 3565 t.Fatal("Error must not be nil") 3566 } 3567 logDone("build - onbuild forbidden from") 3568 } 3569 3570 func TestBuildOnBuildForbiddenMaintainer(t *testing.T) { 3571 name := "testbuildonbuildforbiddenmaintainer" 3572 defer deleteImages(name) 3573 _, err := buildImage(name, 3574 `FROM busybox 3575 ONBUILD MAINTAINER docker.io`, 3576 true) 3577 if err != nil { 3578 if !strings.Contains(err.Error(), "MAINTAINER isn't allowed as an ONBUILD trigger") { 3579 t.Fatalf("Wrong error %v, must be about MAINTAINER forbidden", err) 3580 } 3581 } else { 3582 t.Fatal("Error must not be nil") 3583 } 3584 logDone("build - onbuild forbidden maintainer") 3585 } 3586 3587 // gh #2446 3588 func TestBuildAddToSymlinkDest(t *testing.T) { 3589 name := "testbuildaddtosymlinkdest" 3590 defer deleteImages(name) 3591 ctx, err := fakeContext(`FROM busybox 3592 RUN mkdir /foo 3593 RUN ln -s /foo /bar 3594 ADD foo /bar/ 3595 RUN [ -f /bar/foo ] 3596 RUN [ -f /foo/foo ]`, 3597 map[string]string{ 3598 "foo": "hello", 3599 }) 3600 if err != nil { 3601 t.Fatal(err) 3602 } 3603 defer ctx.Close() 3604 if _, err := buildImageFromContext(name, ctx, true); err != nil { 3605 t.Fatal(err) 3606 } 3607 logDone("build - add to symlink destination") 3608 } 3609 3610 func TestBuildEscapeWhitespace(t *testing.T) { 3611 name := "testbuildescaping" 3612 defer deleteImages(name) 3613 3614 _, err := buildImage(name, ` 3615 FROM busybox 3616 MAINTAINER "Docker \ 3617 IO <io@\ 3618 docker.com>" 3619 `, true) 3620 3621 res, err := inspectField(name, "Author") 3622 3623 if err != nil { 3624 t.Fatal(err) 3625 } 3626 3627 if res != "\"Docker IO <io@docker.com>\"" { 3628 t.Fatalf("Parsed string did not match the escaped string. Got: %q", res) 3629 } 3630 3631 logDone("build - validate escaping whitespace") 3632 } 3633 3634 func TestBuildVerifyIntString(t *testing.T) { 3635 // Verify that strings that look like ints are still passed as strings 3636 name := "testbuildstringing" 3637 defer deleteImages(name) 3638 3639 _, err := buildImage(name, ` 3640 FROM busybox 3641 MAINTAINER 123 3642 `, true) 3643 3644 out, rc, err := runCommandWithOutput(exec.Command(dockerBinary, "inspect", name)) 3645 if rc != 0 || err != nil { 3646 t.Fatalf("Unexcepted error from inspect: rc: %v err: %v", rc, err) 3647 } 3648 3649 if !strings.Contains(out, "\"123\"") { 3650 t.Fatalf("Output does not contain the int as a string:\n%s", out) 3651 } 3652 3653 logDone("build - verify int/strings as strings") 3654 } 3655 3656 func TestBuildDockerignore(t *testing.T) { 3657 name := "testbuilddockerignore" 3658 defer deleteImages(name) 3659 dockerfile := ` 3660 FROM busybox 3661 ADD . /bla 3662 RUN [[ -f /bla/src/x.go ]] 3663 RUN [[ -f /bla/Makefile ]] 3664 RUN [[ ! -e /bla/src/_vendor ]] 3665 RUN [[ ! -e /bla/.gitignore ]] 3666 RUN [[ ! -e /bla/README.md ]] 3667 RUN [[ ! -e /bla/.git ]]` 3668 ctx, err := fakeContext(dockerfile, map[string]string{ 3669 "Makefile": "all:", 3670 ".git/HEAD": "ref: foo", 3671 "src/x.go": "package main", 3672 "src/_vendor/v.go": "package main", 3673 ".gitignore": "", 3674 "README.md": "readme", 3675 ".dockerignore": ".git\npkg\n.gitignore\nsrc/_vendor\n*.md", 3676 }) 3677 defer ctx.Close() 3678 if err != nil { 3679 t.Fatal(err) 3680 } 3681 if _, err := buildImageFromContext(name, ctx, true); err != nil { 3682 t.Fatal(err) 3683 } 3684 logDone("build - test .dockerignore") 3685 } 3686 3687 func TestBuildDockerignoreCleanPaths(t *testing.T) { 3688 name := "testbuilddockerignorecleanpaths" 3689 defer deleteImages(name) 3690 dockerfile := ` 3691 FROM busybox 3692 ADD . /tmp/ 3693 RUN (! ls /tmp/foo) && (! ls /tmp/foo2) && (! ls /tmp/dir1/foo)` 3694 ctx, err := fakeContext(dockerfile, map[string]string{ 3695 "foo": "foo", 3696 "foo2": "foo2", 3697 "dir1/foo": "foo in dir1", 3698 ".dockerignore": "./foo\ndir1//foo\n./dir1/../foo2", 3699 }) 3700 if err != nil { 3701 t.Fatal(err) 3702 } 3703 defer ctx.Close() 3704 if _, err := buildImageFromContext(name, ctx, true); err != nil { 3705 t.Fatal(err) 3706 } 3707 logDone("build - test .dockerignore with clean paths") 3708 } 3709 3710 func TestBuildDockerignoringDockerfile(t *testing.T) { 3711 name := "testbuilddockerignoredockerfile" 3712 defer deleteImages(name) 3713 dockerfile := ` 3714 FROM busybox 3715 ADD . /tmp/ 3716 RUN ! ls /tmp/Dockerfile 3717 RUN ls /tmp/.dockerignore` 3718 ctx, err := fakeContext(dockerfile, map[string]string{ 3719 "Dockerfile": dockerfile, 3720 ".dockerignore": "Dockerfile\n", 3721 }) 3722 if err != nil { 3723 t.Fatal(err) 3724 } 3725 defer ctx.Close() 3726 3727 if _, err = buildImageFromContext(name, ctx, true); err != nil { 3728 t.Fatalf("Didn't ignore Dockerfile correctly:%s", err) 3729 } 3730 3731 // now try it with ./Dockerfile 3732 ctx.Add(".dockerignore", "./Dockerfile\n") 3733 if _, err = buildImageFromContext(name, ctx, true); err != nil { 3734 t.Fatalf("Didn't ignore ./Dockerfile correctly:%s", err) 3735 } 3736 3737 logDone("build - test .dockerignore of Dockerfile") 3738 } 3739 3740 func TestBuildDockerignoringRenamedDockerfile(t *testing.T) { 3741 name := "testbuilddockerignoredockerfile" 3742 defer deleteImages(name) 3743 dockerfile := ` 3744 FROM busybox 3745 ADD . /tmp/ 3746 RUN ls /tmp/Dockerfile 3747 RUN ! ls /tmp/MyDockerfile 3748 RUN ls /tmp/.dockerignore` 3749 ctx, err := fakeContext(dockerfile, map[string]string{ 3750 "Dockerfile": "Should not use me", 3751 "MyDockerfile": dockerfile, 3752 ".dockerignore": "MyDockerfile\n", 3753 }) 3754 if err != nil { 3755 t.Fatal(err) 3756 } 3757 defer ctx.Close() 3758 3759 if _, err = buildImageFromContext(name, ctx, true); err != nil { 3760 t.Fatalf("Didn't ignore MyDockerfile correctly:%s", err) 3761 } 3762 3763 // now try it with ./MyDockerfile 3764 ctx.Add(".dockerignore", "./MyDockerfile\n") 3765 if _, err = buildImageFromContext(name, ctx, true); err != nil { 3766 t.Fatalf("Didn't ignore ./MyDockerfile correctly:%s", err) 3767 } 3768 3769 logDone("build - test .dockerignore of renamed Dockerfile") 3770 } 3771 3772 func TestBuildDockerignoringDockerignore(t *testing.T) { 3773 name := "testbuilddockerignoredockerignore" 3774 defer deleteImages(name) 3775 dockerfile := ` 3776 FROM busybox 3777 ADD . /tmp/ 3778 RUN ! ls /tmp/.dockerignore 3779 RUN ls /tmp/Dockerfile` 3780 ctx, err := fakeContext(dockerfile, map[string]string{ 3781 "Dockerfile": dockerfile, 3782 ".dockerignore": ".dockerignore\n", 3783 }) 3784 defer ctx.Close() 3785 if err != nil { 3786 t.Fatal(err) 3787 } 3788 if _, err = buildImageFromContext(name, ctx, true); err != nil { 3789 t.Fatalf("Didn't ignore .dockerignore correctly:%s", err) 3790 } 3791 logDone("build - test .dockerignore of .dockerignore") 3792 } 3793 3794 func TestBuildDockerignoreTouchDockerfile(t *testing.T) { 3795 var id1 string 3796 var id2 string 3797 3798 name := "testbuilddockerignoretouchdockerfile" 3799 defer deleteImages(name) 3800 dockerfile := ` 3801 FROM busybox 3802 ADD . /tmp/` 3803 ctx, err := fakeContext(dockerfile, map[string]string{ 3804 "Dockerfile": dockerfile, 3805 ".dockerignore": "Dockerfile\n", 3806 }) 3807 defer ctx.Close() 3808 if err != nil { 3809 t.Fatal(err) 3810 } 3811 3812 if id1, err = buildImageFromContext(name, ctx, true); err != nil { 3813 t.Fatalf("Didn't build it correctly:%s", err) 3814 } 3815 3816 if id2, err = buildImageFromContext(name, ctx, true); err != nil { 3817 t.Fatalf("Didn't build it correctly:%s", err) 3818 } 3819 if id1 != id2 { 3820 t.Fatalf("Didn't use the cache - 1") 3821 } 3822 3823 // Now make sure touching Dockerfile doesn't invalidate the cache 3824 if err = ctx.Add("Dockerfile", dockerfile+"\n# hi"); err != nil { 3825 t.Fatalf("Didn't add Dockerfile: %s", err) 3826 } 3827 if id2, err = buildImageFromContext(name, ctx, true); err != nil { 3828 t.Fatalf("Didn't build it correctly:%s", err) 3829 } 3830 if id1 != id2 { 3831 t.Fatalf("Didn't use the cache - 2") 3832 } 3833 3834 // One more time but just 'touch' it instead of changing the content 3835 if err = ctx.Add("Dockerfile", dockerfile+"\n# hi"); err != nil { 3836 t.Fatalf("Didn't add Dockerfile: %s", err) 3837 } 3838 if id2, err = buildImageFromContext(name, ctx, true); err != nil { 3839 t.Fatalf("Didn't build it correctly:%s", err) 3840 } 3841 if id1 != id2 { 3842 t.Fatalf("Didn't use the cache - 3") 3843 } 3844 3845 logDone("build - test .dockerignore touch dockerfile") 3846 } 3847 3848 func TestBuildDockerignoringWholeDir(t *testing.T) { 3849 name := "testbuilddockerignorewholedir" 3850 defer deleteImages(name) 3851 dockerfile := ` 3852 FROM busybox 3853 COPY . / 3854 RUN [[ ! -e /.gitignore ]] 3855 RUN [[ -f /Makefile ]]` 3856 ctx, err := fakeContext(dockerfile, map[string]string{ 3857 "Dockerfile": "FROM scratch", 3858 "Makefile": "all:", 3859 ".dockerignore": ".*\n", 3860 }) 3861 defer ctx.Close() 3862 if err != nil { 3863 t.Fatal(err) 3864 } 3865 if _, err = buildImageFromContext(name, ctx, true); err != nil { 3866 t.Fatal(err) 3867 } 3868 logDone("build - test .dockerignore whole dir with .*") 3869 } 3870 3871 func TestBuildLineBreak(t *testing.T) { 3872 name := "testbuildlinebreak" 3873 defer deleteImages(name) 3874 _, err := buildImage(name, 3875 `FROM busybox 3876 RUN sh -c 'echo root:testpass \ 3877 > /tmp/passwd' 3878 RUN mkdir -p /var/run/sshd 3879 RUN [ "$(cat /tmp/passwd)" = "root:testpass" ] 3880 RUN [ "$(ls -d /var/run/sshd)" = "/var/run/sshd" ]`, 3881 true) 3882 if err != nil { 3883 t.Fatal(err) 3884 } 3885 logDone("build - line break with \\") 3886 } 3887 3888 func TestBuildEOLInLine(t *testing.T) { 3889 name := "testbuildeolinline" 3890 defer deleteImages(name) 3891 _, err := buildImage(name, 3892 `FROM busybox 3893 RUN sh -c 'echo root:testpass > /tmp/passwd' 3894 RUN echo "foo \n bar"; echo "baz" 3895 RUN mkdir -p /var/run/sshd 3896 RUN [ "$(cat /tmp/passwd)" = "root:testpass" ] 3897 RUN [ "$(ls -d /var/run/sshd)" = "/var/run/sshd" ]`, 3898 true) 3899 if err != nil { 3900 t.Fatal(err) 3901 } 3902 logDone("build - end of line in dockerfile instruction") 3903 } 3904 3905 func TestBuildCommentsShebangs(t *testing.T) { 3906 name := "testbuildcomments" 3907 defer deleteImages(name) 3908 _, err := buildImage(name, 3909 `FROM busybox 3910 # This is an ordinary comment. 3911 RUN { echo '#!/bin/sh'; echo 'echo hello world'; } > /hello.sh 3912 RUN [ ! -x /hello.sh ] 3913 # comment with line break \ 3914 RUN chmod +x /hello.sh 3915 RUN [ -x /hello.sh ] 3916 RUN [ "$(cat /hello.sh)" = $'#!/bin/sh\necho hello world' ] 3917 RUN [ "$(/hello.sh)" = "hello world" ]`, 3918 true) 3919 if err != nil { 3920 t.Fatal(err) 3921 } 3922 logDone("build - comments and shebangs") 3923 } 3924 3925 func TestBuildUsersAndGroups(t *testing.T) { 3926 name := "testbuildusers" 3927 defer deleteImages(name) 3928 _, err := buildImage(name, 3929 `FROM busybox 3930 3931 # Make sure our defaults work 3932 RUN [ "$(id -u):$(id -g)/$(id -un):$(id -gn)" = '0:0/root:root' ] 3933 3934 # 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) 3935 USER root 3936 RUN [ "$(id -G):$(id -Gn)" = '0 10:root wheel' ] 3937 3938 # Setup dockerio user and group 3939 RUN echo 'dockerio:x:1001:1001::/bin:/bin/false' >> /etc/passwd 3940 RUN echo 'dockerio:x:1001:' >> /etc/group 3941 3942 # Make sure we can switch to our user and all the information is exactly as we expect it to be 3943 USER dockerio 3944 RUN id -G 3945 RUN id -Gn 3946 RUN [ "$(id -u):$(id -g)/$(id -un):$(id -gn)/$(id -G):$(id -Gn)" = '1001:1001/dockerio:dockerio/1001:dockerio' ] 3947 3948 # Switch back to root and double check that worked exactly as we might expect it to 3949 USER root 3950 RUN [ "$(id -u):$(id -g)/$(id -un):$(id -gn)/$(id -G):$(id -Gn)" = '0:0/root:root/0 10:root wheel' ] 3951 3952 # Add a "supplementary" group for our dockerio user 3953 RUN echo 'supplementary:x:1002:dockerio' >> /etc/group 3954 3955 # ... and then go verify that we get it like we expect 3956 USER dockerio 3957 RUN [ "$(id -u):$(id -g)/$(id -un):$(id -gn)/$(id -G):$(id -Gn)" = '1001:1001/dockerio:dockerio/1001 1002:dockerio supplementary' ] 3958 USER 1001 3959 RUN [ "$(id -u):$(id -g)/$(id -un):$(id -gn)/$(id -G):$(id -Gn)" = '1001:1001/dockerio:dockerio/1001 1002:dockerio supplementary' ] 3960 3961 # super test the new "user:group" syntax 3962 USER dockerio:dockerio 3963 RUN [ "$(id -u):$(id -g)/$(id -un):$(id -gn)/$(id -G):$(id -Gn)" = '1001:1001/dockerio:dockerio/1001:dockerio' ] 3964 USER 1001:dockerio 3965 RUN [ "$(id -u):$(id -g)/$(id -un):$(id -gn)/$(id -G):$(id -Gn)" = '1001:1001/dockerio:dockerio/1001:dockerio' ] 3966 USER dockerio:1001 3967 RUN [ "$(id -u):$(id -g)/$(id -un):$(id -gn)/$(id -G):$(id -Gn)" = '1001:1001/dockerio:dockerio/1001:dockerio' ] 3968 USER 1001:1001 3969 RUN [ "$(id -u):$(id -g)/$(id -un):$(id -gn)/$(id -G):$(id -Gn)" = '1001:1001/dockerio:dockerio/1001:dockerio' ] 3970 USER dockerio:supplementary 3971 RUN [ "$(id -u):$(id -g)/$(id -un):$(id -gn)/$(id -G):$(id -Gn)" = '1001:1002/dockerio:supplementary/1002:supplementary' ] 3972 USER dockerio:1002 3973 RUN [ "$(id -u):$(id -g)/$(id -un):$(id -gn)/$(id -G):$(id -Gn)" = '1001:1002/dockerio:supplementary/1002:supplementary' ] 3974 USER 1001:supplementary 3975 RUN [ "$(id -u):$(id -g)/$(id -un):$(id -gn)/$(id -G):$(id -Gn)" = '1001:1002/dockerio:supplementary/1002:supplementary' ] 3976 USER 1001:1002 3977 RUN [ "$(id -u):$(id -g)/$(id -un):$(id -gn)/$(id -G):$(id -Gn)" = '1001:1002/dockerio:supplementary/1002:supplementary' ] 3978 3979 # make sure unknown uid/gid still works properly 3980 USER 1042:1043 3981 RUN [ "$(id -u):$(id -g)/$(id -un):$(id -gn)/$(id -G):$(id -Gn)" = '1042:1043/1042:1043/1043:1043' ]`, 3982 true) 3983 if err != nil { 3984 t.Fatal(err) 3985 } 3986 logDone("build - users and groups") 3987 } 3988 3989 func TestBuildEnvUsage(t *testing.T) { 3990 name := "testbuildenvusage" 3991 defer deleteImages(name) 3992 dockerfile := `FROM busybox 3993 ENV HOME /root 3994 ENV PATH $HOME/bin:$PATH 3995 ENV PATH /tmp:$PATH 3996 RUN [ "$PATH" = "/tmp:$HOME/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" ] 3997 ENV FOO /foo/baz 3998 ENV BAR /bar 3999 ENV BAZ $BAR 4000 ENV FOOPATH $PATH:$FOO 4001 RUN [ "$BAR" = "$BAZ" ] 4002 RUN [ "$FOOPATH" = "$PATH:/foo/baz" ] 4003 ENV FROM hello/docker/world 4004 ENV TO /docker/world/hello 4005 ADD $FROM $TO 4006 RUN [ "$(cat $TO)" = "hello" ] 4007 ENV abc=def 4008 ENV ghi=$abc 4009 RUN [ "$ghi" = "def" ] 4010 ` 4011 ctx, err := fakeContext(dockerfile, map[string]string{ 4012 "hello/docker/world": "hello", 4013 }) 4014 if err != nil { 4015 t.Fatal(err) 4016 } 4017 defer ctx.Close() 4018 4019 _, err = buildImageFromContext(name, ctx, true) 4020 if err != nil { 4021 t.Fatal(err) 4022 } 4023 logDone("build - environment variables usage") 4024 } 4025 4026 func TestBuildEnvUsage2(t *testing.T) { 4027 name := "testbuildenvusage2" 4028 defer deleteImages(name) 4029 dockerfile := `FROM busybox 4030 ENV abc=def 4031 RUN [ "$abc" = "def" ] 4032 ENV def="hello world" 4033 RUN [ "$def" = "hello world" ] 4034 ENV def=hello\ world 4035 RUN [ "$def" = "hello world" ] 4036 ENV v1=abc v2="hi there" 4037 RUN [ "$v1" = "abc" ] 4038 RUN [ "$v2" = "hi there" ] 4039 ENV v3='boogie nights' v4="with'quotes too" 4040 RUN [ "$v3" = "boogie nights" ] 4041 RUN [ "$v4" = "with'quotes too" ] 4042 ENV abc=zzz FROM=hello/docker/world 4043 ENV abc=zzz TO=/docker/world/hello 4044 ADD $FROM $TO 4045 RUN [ "$(cat $TO)" = "hello" ] 4046 ENV abc "zzz" 4047 RUN [ $abc = "zzz" ] 4048 ENV abc 'yyy' 4049 RUN [ $abc = 'yyy' ] 4050 ENV abc= 4051 RUN [ "$abc" = "" ] 4052 4053 # use grep to make sure if the builder substitutes \$foo by mistake 4054 # we don't get a false positive 4055 ENV abc=\$foo 4056 RUN [ "$abc" = "\$foo" ] && (echo "$abc" | grep foo) 4057 ENV abc \$foo 4058 RUN [ "$abc" = "\$foo" ] && (echo "$abc" | grep foo) 4059 4060 ENV abc=\'foo\' 4061 RUN [ "$abc" = "'foo'" ] 4062 ENV abc=\"foo\" 4063 RUN [ "$abc" = "\"foo\"" ] 4064 ENV abc "foo" 4065 RUN [ "$abc" = "foo" ] 4066 ENV abc 'foo' 4067 RUN [ "$abc" = 'foo' ] 4068 ENV abc \'foo\' 4069 RUN [ "$abc" = "'foo'" ] 4070 ENV abc \"foo\" 4071 RUN [ "$abc" = '"foo"' ] 4072 4073 ENV e1=bar 4074 ENV e2=$e1 4075 ENV e3=$e11 4076 ENV e4=\$e1 4077 ENV e5=\$e11 4078 RUN [ "$e0,$e1,$e2,$e3,$e4,$e5" = ',bar,bar,,$e1,$e11' ] 4079 4080 ENV ee1 bar 4081 ENV ee2 $ee1 4082 ENV ee3 $ee11 4083 ENV ee4 \$ee1 4084 ENV ee5 \$ee11 4085 RUN [ "$ee1,$ee2,$ee3,$ee4,$ee5" = 'bar,bar,,$ee1,$ee11' ] 4086 4087 ENV eee1="foo" 4088 ENV eee2='foo' 4089 ENV eee3 "foo" 4090 ENV eee4 'foo' 4091 RUN [ "$eee1,$eee2,$eee3,$eee4" = 'foo,foo,foo,foo' ] 4092 4093 ` 4094 ctx, err := fakeContext(dockerfile, map[string]string{ 4095 "hello/docker/world": "hello", 4096 }) 4097 if err != nil { 4098 t.Fatal(err) 4099 } 4100 defer ctx.Close() 4101 4102 _, err = buildImageFromContext(name, ctx, true) 4103 if err != nil { 4104 t.Fatal(err) 4105 } 4106 logDone("build - environment variables usage2") 4107 } 4108 4109 func TestBuildAddScript(t *testing.T) { 4110 name := "testbuildaddscript" 4111 defer deleteImages(name) 4112 dockerfile := ` 4113 FROM busybox 4114 ADD test /test 4115 RUN ["chmod","+x","/test"] 4116 RUN ["/test"] 4117 RUN [ "$(cat /testfile)" = 'test!' ]` 4118 ctx, err := fakeContext(dockerfile, map[string]string{ 4119 "test": "#!/bin/sh\necho 'test!' > /testfile", 4120 }) 4121 if err != nil { 4122 t.Fatal(err) 4123 } 4124 defer ctx.Close() 4125 4126 _, err = buildImageFromContext(name, ctx, true) 4127 if err != nil { 4128 t.Fatal(err) 4129 } 4130 logDone("build - add and run script") 4131 } 4132 4133 func TestBuildAddTar(t *testing.T) { 4134 name := "testbuildaddtar" 4135 defer deleteImages(name) 4136 4137 ctx := func() *FakeContext { 4138 dockerfile := ` 4139 FROM busybox 4140 ADD test.tar / 4141 RUN cat /test/foo | grep Hi 4142 ADD test.tar /test.tar 4143 RUN cat /test.tar/test/foo | grep Hi 4144 ADD test.tar /unlikely-to-exist 4145 RUN cat /unlikely-to-exist/test/foo | grep Hi 4146 ADD test.tar /unlikely-to-exist-trailing-slash/ 4147 RUN cat /unlikely-to-exist-trailing-slash/test/foo | grep Hi 4148 RUN mkdir /existing-directory 4149 ADD test.tar /existing-directory 4150 RUN cat /existing-directory/test/foo | grep Hi 4151 ADD test.tar /existing-directory-trailing-slash/ 4152 RUN cat /existing-directory-trailing-slash/test/foo | grep Hi` 4153 tmpDir, err := ioutil.TempDir("", "fake-context") 4154 testTar, err := os.Create(filepath.Join(tmpDir, "test.tar")) 4155 if err != nil { 4156 t.Fatalf("failed to create test.tar archive: %v", err) 4157 } 4158 defer testTar.Close() 4159 4160 tw := tar.NewWriter(testTar) 4161 4162 if err := tw.WriteHeader(&tar.Header{ 4163 Name: "test/foo", 4164 Size: 2, 4165 }); err != nil { 4166 t.Fatalf("failed to write tar file header: %v", err) 4167 } 4168 if _, err := tw.Write([]byte("Hi")); err != nil { 4169 t.Fatalf("failed to write tar file content: %v", err) 4170 } 4171 if err := tw.Close(); err != nil { 4172 t.Fatalf("failed to close tar archive: %v", err) 4173 } 4174 4175 if err := ioutil.WriteFile(filepath.Join(tmpDir, "Dockerfile"), []byte(dockerfile), 0644); err != nil { 4176 t.Fatalf("failed to open destination dockerfile: %v", err) 4177 } 4178 return fakeContextFromDir(tmpDir) 4179 }() 4180 defer ctx.Close() 4181 4182 if _, err := buildImageFromContext(name, ctx, true); err != nil { 4183 t.Fatalf("build failed to complete for TestBuildAddTar: %v", err) 4184 } 4185 4186 logDone("build - ADD tar") 4187 } 4188 4189 func TestBuildAddTarXz(t *testing.T) { 4190 name := "testbuildaddtarxz" 4191 defer deleteImages(name) 4192 4193 ctx := func() *FakeContext { 4194 dockerfile := ` 4195 FROM busybox 4196 ADD test.tar.xz / 4197 RUN cat /test/foo | grep Hi` 4198 tmpDir, err := ioutil.TempDir("", "fake-context") 4199 testTar, err := os.Create(filepath.Join(tmpDir, "test.tar")) 4200 if err != nil { 4201 t.Fatalf("failed to create test.tar archive: %v", err) 4202 } 4203 defer testTar.Close() 4204 4205 tw := tar.NewWriter(testTar) 4206 4207 if err := tw.WriteHeader(&tar.Header{ 4208 Name: "test/foo", 4209 Size: 2, 4210 }); err != nil { 4211 t.Fatalf("failed to write tar file header: %v", err) 4212 } 4213 if _, err := tw.Write([]byte("Hi")); err != nil { 4214 t.Fatalf("failed to write tar file content: %v", err) 4215 } 4216 if err := tw.Close(); err != nil { 4217 t.Fatalf("failed to close tar archive: %v", err) 4218 } 4219 xzCompressCmd := exec.Command("xz", "-k", "test.tar") 4220 xzCompressCmd.Dir = tmpDir 4221 out, _, err := runCommandWithOutput(xzCompressCmd) 4222 if err != nil { 4223 t.Fatal(err, out) 4224 } 4225 4226 if err := ioutil.WriteFile(filepath.Join(tmpDir, "Dockerfile"), []byte(dockerfile), 0644); err != nil { 4227 t.Fatalf("failed to open destination dockerfile: %v", err) 4228 } 4229 return fakeContextFromDir(tmpDir) 4230 }() 4231 4232 defer ctx.Close() 4233 4234 if _, err := buildImageFromContext(name, ctx, true); err != nil { 4235 t.Fatalf("build failed to complete for TestBuildAddTarXz: %v", err) 4236 } 4237 4238 logDone("build - ADD tar.xz") 4239 } 4240 4241 func TestBuildAddTarXzGz(t *testing.T) { 4242 name := "testbuildaddtarxzgz" 4243 defer deleteImages(name) 4244 4245 ctx := func() *FakeContext { 4246 dockerfile := ` 4247 FROM busybox 4248 ADD test.tar.xz.gz / 4249 RUN ls /test.tar.xz.gz` 4250 tmpDir, err := ioutil.TempDir("", "fake-context") 4251 testTar, err := os.Create(filepath.Join(tmpDir, "test.tar")) 4252 if err != nil { 4253 t.Fatalf("failed to create test.tar archive: %v", err) 4254 } 4255 defer testTar.Close() 4256 4257 tw := tar.NewWriter(testTar) 4258 4259 if err := tw.WriteHeader(&tar.Header{ 4260 Name: "test/foo", 4261 Size: 2, 4262 }); err != nil { 4263 t.Fatalf("failed to write tar file header: %v", err) 4264 } 4265 if _, err := tw.Write([]byte("Hi")); err != nil { 4266 t.Fatalf("failed to write tar file content: %v", err) 4267 } 4268 if err := tw.Close(); err != nil { 4269 t.Fatalf("failed to close tar archive: %v", err) 4270 } 4271 4272 xzCompressCmd := exec.Command("xz", "-k", "test.tar") 4273 xzCompressCmd.Dir = tmpDir 4274 out, _, err := runCommandWithOutput(xzCompressCmd) 4275 if err != nil { 4276 t.Fatal(err, out) 4277 } 4278 4279 gzipCompressCmd := exec.Command("gzip", "test.tar.xz") 4280 gzipCompressCmd.Dir = tmpDir 4281 out, _, err = runCommandWithOutput(gzipCompressCmd) 4282 if err != nil { 4283 t.Fatal(err, out) 4284 } 4285 4286 if err := ioutil.WriteFile(filepath.Join(tmpDir, "Dockerfile"), []byte(dockerfile), 0644); err != nil { 4287 t.Fatalf("failed to open destination dockerfile: %v", err) 4288 } 4289 return fakeContextFromDir(tmpDir) 4290 }() 4291 4292 defer ctx.Close() 4293 4294 if _, err := buildImageFromContext(name, ctx, true); err != nil { 4295 t.Fatalf("build failed to complete for TestBuildAddTarXz: %v", err) 4296 } 4297 4298 logDone("build - ADD tar.xz.gz") 4299 } 4300 4301 func TestBuildFromGIT(t *testing.T) { 4302 name := "testbuildfromgit" 4303 defer deleteImages(name) 4304 git, err := fakeGIT("repo", map[string]string{ 4305 "Dockerfile": `FROM busybox 4306 ADD first /first 4307 RUN [ -f /first ] 4308 MAINTAINER docker`, 4309 "first": "test git data", 4310 }, true) 4311 if err != nil { 4312 t.Fatal(err) 4313 } 4314 defer git.Close() 4315 4316 _, err = buildImageFromPath(name, git.RepoURL, true) 4317 if err != nil { 4318 t.Fatal(err) 4319 } 4320 res, err := inspectField(name, "Author") 4321 if err != nil { 4322 t.Fatal(err) 4323 } 4324 if res != "docker" { 4325 t.Fatalf("Maintainer should be docker, got %s", res) 4326 } 4327 logDone("build - build from GIT") 4328 } 4329 4330 func TestBuildCleanupCmdOnEntrypoint(t *testing.T) { 4331 name := "testbuildcmdcleanuponentrypoint" 4332 defer deleteImages(name) 4333 if _, err := buildImage(name, 4334 `FROM scratch 4335 CMD ["test"] 4336 ENTRYPOINT ["echo"]`, 4337 true); err != nil { 4338 t.Fatal(err) 4339 } 4340 if _, err := buildImage(name, 4341 fmt.Sprintf(`FROM %s 4342 ENTRYPOINT ["cat"]`, name), 4343 true); err != nil { 4344 t.Fatal(err) 4345 } 4346 res, err := inspectField(name, "Config.Cmd") 4347 if err != nil { 4348 t.Fatal(err) 4349 } 4350 if expected := "<no value>"; res != expected { 4351 t.Fatalf("Cmd %s, expected %s", res, expected) 4352 } 4353 res, err = inspectField(name, "Config.Entrypoint") 4354 if err != nil { 4355 t.Fatal(err) 4356 } 4357 if expected := "[cat]"; res != expected { 4358 t.Fatalf("Entrypoint %s, expected %s", res, expected) 4359 } 4360 logDone("build - cleanup cmd on ENTRYPOINT") 4361 } 4362 4363 func TestBuildClearCmd(t *testing.T) { 4364 name := "testbuildclearcmd" 4365 defer deleteImages(name) 4366 _, err := buildImage(name, 4367 `From scratch 4368 ENTRYPOINT ["/bin/bash"] 4369 CMD []`, 4370 true) 4371 if err != nil { 4372 t.Fatal(err) 4373 } 4374 res, err := inspectFieldJSON(name, "Config.Cmd") 4375 if err != nil { 4376 t.Fatal(err) 4377 } 4378 if res != "[]" { 4379 t.Fatalf("Cmd %s, expected %s", res, "[]") 4380 } 4381 logDone("build - clearcmd") 4382 } 4383 4384 func TestBuildEmptyCmd(t *testing.T) { 4385 name := "testbuildemptycmd" 4386 defer deleteImages(name) 4387 if _, err := buildImage(name, "FROM scratch\nMAINTAINER quux\n", true); err != nil { 4388 t.Fatal(err) 4389 } 4390 res, err := inspectFieldJSON(name, "Config.Cmd") 4391 if err != nil { 4392 t.Fatal(err) 4393 } 4394 if res != "null" { 4395 t.Fatalf("Cmd %s, expected %s", res, "null") 4396 } 4397 logDone("build - empty cmd") 4398 } 4399 4400 func TestBuildOnBuildOutput(t *testing.T) { 4401 name := "testbuildonbuildparent" 4402 defer deleteImages(name) 4403 if _, err := buildImage(name, "FROM busybox\nONBUILD RUN echo foo\n", true); err != nil { 4404 t.Fatal(err) 4405 } 4406 4407 childname := "testbuildonbuildchild" 4408 defer deleteImages(childname) 4409 4410 _, out, err := buildImageWithOut(name, "FROM "+name+"\nMAINTAINER quux\n", true) 4411 if err != nil { 4412 t.Fatal(err) 4413 } 4414 4415 if !strings.Contains(out, "Trigger 0, RUN echo foo") { 4416 t.Fatal("failed to find the ONBUILD output", out) 4417 } 4418 4419 logDone("build - onbuild output") 4420 } 4421 4422 func TestBuildInvalidTag(t *testing.T) { 4423 name := "abcd:" + makeRandomString(200) 4424 defer deleteImages(name) 4425 _, out, err := buildImageWithOut(name, "FROM scratch\nMAINTAINER quux\n", true) 4426 // if the error doesnt check for illegal tag name, or the image is built 4427 // then this should fail 4428 if !strings.Contains(out, "Illegal tag name") || strings.Contains(out, "Sending build context to Docker daemon") { 4429 t.Fatalf("failed to stop before building. Error: %s, Output: %s", err, out) 4430 } 4431 logDone("build - invalid tag") 4432 } 4433 4434 func TestBuildCmdShDashC(t *testing.T) { 4435 name := "testbuildcmdshc" 4436 defer deleteImages(name) 4437 if _, err := buildImage(name, "FROM busybox\nCMD echo cmd\n", true); err != nil { 4438 t.Fatal(err) 4439 } 4440 4441 res, err := inspectFieldJSON(name, "Config.Cmd") 4442 if err != nil { 4443 t.Fatal(err, res) 4444 } 4445 4446 expected := `["/bin/sh","-c","echo cmd"]` 4447 4448 if res != expected { 4449 t.Fatalf("Expected value %s not in Config.Cmd: %s", expected, res) 4450 } 4451 4452 logDone("build - cmd should have sh -c for non-json") 4453 } 4454 4455 func TestBuildCmdSpaces(t *testing.T) { 4456 // Test to make sure that when we strcat arrays we take into account 4457 // the arg separator to make sure ["echo","hi"] and ["echo hi"] don't 4458 // look the same 4459 name := "testbuildcmdspaces" 4460 defer deleteImages(name) 4461 var id1 string 4462 var id2 string 4463 var err error 4464 4465 if id1, err = buildImage(name, "FROM busybox\nCMD [\"echo hi\"]\n", true); err != nil { 4466 t.Fatal(err) 4467 } 4468 4469 if id2, err = buildImage(name, "FROM busybox\nCMD [\"echo\", \"hi\"]\n", true); err != nil { 4470 t.Fatal(err) 4471 } 4472 4473 if id1 == id2 { 4474 t.Fatal("Should not have resulted in the same CMD") 4475 } 4476 4477 // Now do the same with ENTRYPOINT 4478 if id1, err = buildImage(name, "FROM busybox\nENTRYPOINT [\"echo hi\"]\n", true); err != nil { 4479 t.Fatal(err) 4480 } 4481 4482 if id2, err = buildImage(name, "FROM busybox\nENTRYPOINT [\"echo\", \"hi\"]\n", true); err != nil { 4483 t.Fatal(err) 4484 } 4485 4486 if id1 == id2 { 4487 t.Fatal("Should not have resulted in the same ENTRYPOINT") 4488 } 4489 4490 logDone("build - cmd with spaces") 4491 } 4492 4493 func TestBuildCmdJSONNoShDashC(t *testing.T) { 4494 name := "testbuildcmdjson" 4495 defer deleteImages(name) 4496 if _, err := buildImage(name, "FROM busybox\nCMD [\"echo\", \"cmd\"]", true); err != nil { 4497 t.Fatal(err) 4498 } 4499 4500 res, err := inspectFieldJSON(name, "Config.Cmd") 4501 if err != nil { 4502 t.Fatal(err, res) 4503 } 4504 4505 expected := `["echo","cmd"]` 4506 4507 if res != expected { 4508 t.Fatalf("Expected value %s not in Config.Cmd: %s", expected, res) 4509 } 4510 4511 logDone("build - cmd should not have /bin/sh -c for json") 4512 } 4513 4514 func TestBuildErrorInvalidInstruction(t *testing.T) { 4515 name := "testbuildignoreinvalidinstruction" 4516 defer deleteImages(name) 4517 4518 out, _, err := buildImageWithOut(name, "FROM busybox\nfoo bar", true) 4519 if err == nil { 4520 t.Fatalf("Should have failed: %s", out) 4521 } 4522 4523 logDone("build - error invalid Dockerfile instruction") 4524 } 4525 4526 func TestBuildEntrypointInheritance(t *testing.T) { 4527 defer deleteImages("parent", "child") 4528 defer deleteAllContainers() 4529 4530 if _, err := buildImage("parent", ` 4531 FROM busybox 4532 ENTRYPOINT exit 130 4533 `, true); err != nil { 4534 t.Fatal(err) 4535 } 4536 4537 status, _ := runCommand(exec.Command(dockerBinary, "run", "parent")) 4538 4539 if status != 130 { 4540 t.Fatalf("expected exit code 130 but received %d", status) 4541 } 4542 4543 if _, err := buildImage("child", ` 4544 FROM parent 4545 ENTRYPOINT exit 5 4546 `, true); err != nil { 4547 t.Fatal(err) 4548 } 4549 4550 status, _ = runCommand(exec.Command(dockerBinary, "run", "child")) 4551 4552 if status != 5 { 4553 t.Fatalf("expected exit code 5 but received %d", status) 4554 } 4555 4556 logDone("build - clear entrypoint") 4557 } 4558 4559 func TestBuildEntrypointInheritanceInspect(t *testing.T) { 4560 var ( 4561 name = "testbuildepinherit" 4562 name2 = "testbuildepinherit2" 4563 expected = `["/bin/sh","-c","echo quux"]` 4564 ) 4565 4566 defer deleteImages(name, name2) 4567 defer deleteAllContainers() 4568 4569 if _, err := buildImage(name, "FROM busybox\nENTRYPOINT /foo/bar", true); err != nil { 4570 t.Fatal(err) 4571 } 4572 4573 if _, err := buildImage(name2, fmt.Sprintf("FROM %s\nENTRYPOINT echo quux", name), true); err != nil { 4574 t.Fatal(err) 4575 } 4576 4577 res, err := inspectFieldJSON(name2, "Config.Entrypoint") 4578 if err != nil { 4579 t.Fatal(err, res) 4580 } 4581 4582 if res != expected { 4583 t.Fatalf("Expected value %s not in Config.Entrypoint: %s", expected, res) 4584 } 4585 4586 out, _, err := runCommandWithOutput(exec.Command(dockerBinary, "run", "-t", name2)) 4587 if err != nil { 4588 t.Fatal(err, out) 4589 } 4590 4591 expected = "quux" 4592 4593 if strings.TrimSpace(out) != expected { 4594 t.Fatalf("Expected output is %s, got %s", expected, out) 4595 } 4596 4597 logDone("build - entrypoint override inheritance properly") 4598 } 4599 4600 func TestBuildRunShEntrypoint(t *testing.T) { 4601 name := "testbuildentrypoint" 4602 defer deleteImages(name) 4603 _, err := buildImage(name, 4604 `FROM busybox 4605 ENTRYPOINT /bin/echo`, 4606 true) 4607 if err != nil { 4608 t.Fatal(err) 4609 } 4610 4611 out, _, err := runCommandWithOutput(exec.Command(dockerBinary, "run", "--rm", name)) 4612 4613 if err != nil { 4614 t.Fatal(err, out) 4615 } 4616 4617 logDone("build - entrypoint with /bin/echo running successfully") 4618 } 4619 4620 func TestBuildExoticShellInterpolation(t *testing.T) { 4621 name := "testbuildexoticshellinterpolation" 4622 defer deleteImages(name) 4623 4624 _, err := buildImage(name, ` 4625 FROM busybox 4626 4627 ENV SOME_VAR a.b.c 4628 4629 RUN [ "$SOME_VAR" = 'a.b.c' ] 4630 RUN [ "${SOME_VAR}" = 'a.b.c' ] 4631 RUN [ "${SOME_VAR%.*}" = 'a.b' ] 4632 RUN [ "${SOME_VAR%%.*}" = 'a' ] 4633 RUN [ "${SOME_VAR#*.}" = 'b.c' ] 4634 RUN [ "${SOME_VAR##*.}" = 'c' ] 4635 RUN [ "${SOME_VAR/c/d}" = 'a.b.d' ] 4636 RUN [ "${#SOME_VAR}" = '5' ] 4637 4638 RUN [ "${SOME_UNSET_VAR:-$SOME_VAR}" = 'a.b.c' ] 4639 RUN [ "${SOME_VAR:+Version: ${SOME_VAR}}" = 'Version: a.b.c' ] 4640 RUN [ "${SOME_UNSET_VAR:+${SOME_VAR}}" = '' ] 4641 RUN [ "${SOME_UNSET_VAR:-${SOME_VAR:-d.e.f}}" = 'a.b.c' ] 4642 `, false) 4643 if err != nil { 4644 t.Fatal(err) 4645 } 4646 4647 logDone("build - exotic shell interpolation") 4648 } 4649 4650 func TestBuildVerifySingleQuoteFails(t *testing.T) { 4651 // This testcase is supposed to generate an error because the 4652 // JSON array we're passing in on the CMD uses single quotes instead 4653 // of double quotes (per the JSON spec). This means we interpret it 4654 // as a "string" insead of "JSON array" and pass it on to "sh -c" and 4655 // it should barf on it. 4656 name := "testbuildsinglequotefails" 4657 defer deleteImages(name) 4658 defer deleteAllContainers() 4659 4660 _, err := buildImage(name, 4661 `FROM busybox 4662 CMD [ '/bin/sh', '-c', 'echo hi' ]`, 4663 true) 4664 _, _, err = runCommandWithOutput(exec.Command(dockerBinary, "run", "--rm", name)) 4665 4666 if err == nil { 4667 t.Fatal("The image was not supposed to be able to run") 4668 } 4669 4670 logDone("build - verify single quotes break the build") 4671 } 4672 4673 func TestBuildVerboseOut(t *testing.T) { 4674 name := "testbuildverboseout" 4675 defer deleteImages(name) 4676 4677 _, out, err := buildImageWithOut(name, 4678 `FROM busybox 4679 RUN echo 123`, 4680 false) 4681 4682 if err != nil { 4683 t.Fatal(err) 4684 } 4685 if !strings.Contains(out, "\n123\n") { 4686 t.Fatalf("Output should contain %q: %q", "123", out) 4687 } 4688 4689 logDone("build - verbose output from commands") 4690 } 4691 4692 func TestBuildWithTabs(t *testing.T) { 4693 name := "testbuildwithtabs" 4694 defer deleteImages(name) 4695 _, err := buildImage(name, 4696 "FROM busybox\nRUN echo\tone\t\ttwo", true) 4697 if err != nil { 4698 t.Fatal(err) 4699 } 4700 res, err := inspectFieldJSON(name, "ContainerConfig.Cmd") 4701 if err != nil { 4702 t.Fatal(err) 4703 } 4704 expected1 := `["/bin/sh","-c","echo\tone\t\ttwo"]` 4705 expected2 := `["/bin/sh","-c","echo\u0009one\u0009\u0009two"]` // syntactically equivalent, and what Go 1.3 generates 4706 if res != expected1 && res != expected2 { 4707 t.Fatalf("Missing tabs.\nGot: %s\nExp: %s or %s", res, expected1, expected2) 4708 } 4709 logDone("build - with tabs") 4710 } 4711 4712 func TestBuildLabels(t *testing.T) { 4713 name := "testbuildlabel" 4714 expected := `{"License":"GPL","Vendor":"Acme"}` 4715 defer deleteImages(name) 4716 _, err := buildImage(name, 4717 `FROM busybox 4718 LABEL Vendor=Acme 4719 LABEL License GPL`, 4720 true) 4721 if err != nil { 4722 t.Fatal(err) 4723 } 4724 res, err := inspectFieldJSON(name, "Config.Labels") 4725 if err != nil { 4726 t.Fatal(err) 4727 } 4728 if res != expected { 4729 t.Fatalf("Labels %s, expected %s", res, expected) 4730 } 4731 logDone("build - label") 4732 } 4733 4734 func TestBuildLabelsCache(t *testing.T) { 4735 name := "testbuildlabelcache" 4736 defer deleteImages(name) 4737 4738 id1, err := buildImage(name, 4739 `FROM busybox 4740 LABEL Vendor=Acme`, false) 4741 if err != nil { 4742 t.Fatalf("Build 1 should have worked: %v", err) 4743 } 4744 4745 id2, err := buildImage(name, 4746 `FROM busybox 4747 LABEL Vendor=Acme`, true) 4748 if err != nil || id1 != id2 { 4749 t.Fatalf("Build 2 should have worked & used cache(%s,%s): %v", id1, id2, err) 4750 } 4751 4752 id2, err = buildImage(name, 4753 `FROM busybox 4754 LABEL Vendor=Acme1`, true) 4755 if err != nil || id1 == id2 { 4756 t.Fatalf("Build 3 should have worked & NOT used cache(%s,%s): %v", id1, id2, err) 4757 } 4758 4759 id2, err = buildImage(name, 4760 `FROM busybox 4761 LABEL Vendor Acme`, true) // Note: " " and "=" should be same 4762 if err != nil || id1 != id2 { 4763 t.Fatalf("Build 4 should have worked & used cache(%s,%s): %v", id1, id2, err) 4764 } 4765 4766 // Now make sure the cache isn't used by mistake 4767 id1, err = buildImage(name, 4768 `FROM busybox 4769 LABEL f1=b1 f2=b2`, false) 4770 if err != nil { 4771 t.Fatalf("Build 5 should have worked: %q", err) 4772 } 4773 4774 id2, err = buildImage(name, 4775 `FROM busybox 4776 LABEL f1="b1 f2=b2"`, true) 4777 if err != nil || id1 == id2 { 4778 t.Fatalf("Build 6 should have worked & NOT used the cache(%s,%s): %q", id1, id2, err) 4779 } 4780 4781 logDone("build - label cache") 4782 } 4783 4784 func TestBuildStderr(t *testing.T) { 4785 // This test just makes sure that no non-error output goes 4786 // to stderr 4787 name := "testbuildstderr" 4788 defer deleteImages(name) 4789 _, _, stderr, err := buildImageWithStdoutStderr(name, 4790 "FROM busybox\nRUN echo one", true) 4791 if err != nil { 4792 t.Fatal(err) 4793 } 4794 4795 if runtime.GOOS == "windows" { 4796 // stderr might contain a security warning on windows 4797 lines := strings.Split(stderr, "\n") 4798 for _, v := range lines { 4799 if v != "" && !strings.Contains(v, "SECURITY WARNING:") { 4800 t.Fatalf("Stderr contains unexpected output line: %q", v) 4801 } 4802 } 4803 } else { 4804 if stderr != "" { 4805 t.Fatalf("Stderr should have been empty, instead its: %q", stderr) 4806 } 4807 } 4808 logDone("build - testing stderr") 4809 } 4810 4811 func TestBuildChownSingleFile(t *testing.T) { 4812 testRequires(t, UnixCli) // test uses chown: not available on windows 4813 4814 name := "testbuildchownsinglefile" 4815 defer deleteImages(name) 4816 4817 ctx, err := fakeContext(` 4818 FROM busybox 4819 COPY test / 4820 RUN ls -l /test 4821 RUN [ $(ls -l /test | awk '{print $3":"$4}') = 'root:root' ] 4822 `, map[string]string{ 4823 "test": "test", 4824 }) 4825 if err != nil { 4826 t.Fatal(err) 4827 } 4828 defer ctx.Close() 4829 4830 if err := os.Chown(filepath.Join(ctx.Dir, "test"), 4242, 4242); err != nil { 4831 t.Fatal(err) 4832 } 4833 4834 if _, err := buildImageFromContext(name, ctx, true); err != nil { 4835 t.Fatal(err) 4836 } 4837 4838 logDone("build - change permission on single file") 4839 } 4840 4841 func TestBuildSymlinkBreakout(t *testing.T) { 4842 name := "testbuildsymlinkbreakout" 4843 tmpdir, err := ioutil.TempDir("", name) 4844 if err != nil { 4845 t.Fatal(err) 4846 } 4847 defer os.RemoveAll(tmpdir) 4848 ctx := filepath.Join(tmpdir, "context") 4849 if err := os.MkdirAll(ctx, 0755); err != nil { 4850 t.Fatal(err) 4851 } 4852 if err := ioutil.WriteFile(filepath.Join(ctx, "Dockerfile"), []byte(` 4853 from busybox 4854 add symlink.tar / 4855 add inject /symlink/ 4856 `), 0644); err != nil { 4857 t.Fatal(err) 4858 } 4859 inject := filepath.Join(ctx, "inject") 4860 if err := ioutil.WriteFile(inject, nil, 0644); err != nil { 4861 t.Fatal(err) 4862 } 4863 f, err := os.Create(filepath.Join(ctx, "symlink.tar")) 4864 if err != nil { 4865 t.Fatal(err) 4866 } 4867 w := tar.NewWriter(f) 4868 w.WriteHeader(&tar.Header{ 4869 Name: "symlink2", 4870 Typeflag: tar.TypeSymlink, 4871 Linkname: "/../../../../../../../../../../../../../../", 4872 Uid: os.Getuid(), 4873 Gid: os.Getgid(), 4874 }) 4875 w.WriteHeader(&tar.Header{ 4876 Name: "symlink", 4877 Typeflag: tar.TypeSymlink, 4878 Linkname: filepath.Join("symlink2", tmpdir), 4879 Uid: os.Getuid(), 4880 Gid: os.Getgid(), 4881 }) 4882 w.Close() 4883 f.Close() 4884 if _, err := buildImageFromContext(name, fakeContextFromDir(ctx), false); err != nil { 4885 t.Fatal(err) 4886 } 4887 if _, err := os.Lstat(filepath.Join(tmpdir, "inject")); err == nil { 4888 t.Fatal("symlink breakout - inject") 4889 } else if !os.IsNotExist(err) { 4890 t.Fatalf("unexpected error: %v", err) 4891 } 4892 logDone("build - symlink breakout") 4893 } 4894 4895 func TestBuildXZHost(t *testing.T) { 4896 name := "testbuildxzhost" 4897 defer deleteImages(name) 4898 4899 ctx, err := fakeContext(` 4900 FROM busybox 4901 ADD xz /usr/local/sbin/ 4902 RUN chmod 755 /usr/local/sbin/xz 4903 ADD test.xz / 4904 RUN [ ! -e /injected ]`, 4905 map[string]string{ 4906 "test.xz": "\xfd\x37\x7a\x58\x5a\x00\x00\x04\xe6\xd6\xb4\x46\x02\x00" + 4907 "\x21\x01\x16\x00\x00\x00\x74\x2f\xe5\xa3\x01\x00\x3f\xfd" + 4908 "\x37\x7a\x58\x5a\x00\x00\x04\xe6\xd6\xb4\x46\x02\x00\x21", 4909 "xz": "#!/bin/sh\ntouch /injected", 4910 }) 4911 4912 if err != nil { 4913 t.Fatal(err) 4914 } 4915 defer ctx.Close() 4916 4917 if _, err := buildImageFromContext(name, ctx, true); err != nil { 4918 t.Fatal(err) 4919 } 4920 4921 logDone("build - xz host is being used") 4922 } 4923 4924 func TestBuildVolumesRetainContents(t *testing.T) { 4925 var ( 4926 name = "testbuildvolumescontent" 4927 expected = "some text" 4928 ) 4929 defer deleteImages(name) 4930 ctx, err := fakeContext(` 4931 FROM busybox 4932 COPY content /foo/file 4933 VOLUME /foo 4934 CMD cat /foo/file`, 4935 map[string]string{ 4936 "content": expected, 4937 }) 4938 if err != nil { 4939 t.Fatal(err) 4940 } 4941 defer ctx.Close() 4942 4943 if _, err := buildImageFromContext(name, ctx, false); err != nil { 4944 t.Fatal(err) 4945 } 4946 4947 out, _, err := runCommandWithOutput(exec.Command(dockerBinary, "run", "--rm", name)) 4948 if err != nil { 4949 t.Fatal(err) 4950 } 4951 if out != expected { 4952 t.Fatalf("expected file contents for /foo/file to be %q but received %q", expected, out) 4953 } 4954 4955 logDone("build - volumes retain contents in build") 4956 } 4957 4958 func TestBuildRenamedDockerfile(t *testing.T) { 4959 defer deleteAllContainers() 4960 4961 ctx, err := fakeContext(`FROM busybox 4962 RUN echo from Dockerfile`, 4963 map[string]string{ 4964 "Dockerfile": "FROM busybox\nRUN echo from Dockerfile", 4965 "files/Dockerfile": "FROM busybox\nRUN echo from files/Dockerfile", 4966 "files/dFile": "FROM busybox\nRUN echo from files/dFile", 4967 "dFile": "FROM busybox\nRUN echo from dFile", 4968 "files/dFile2": "FROM busybox\nRUN echo from files/dFile2", 4969 }) 4970 defer ctx.Close() 4971 if err != nil { 4972 t.Fatal(err) 4973 } 4974 4975 out, _, err := dockerCmdInDir(t, ctx.Dir, "build", "-t", "test1", ".") 4976 if err != nil { 4977 t.Fatalf("Failed to build: %s\n%s", out, err) 4978 } 4979 if !strings.Contains(out, "from Dockerfile") { 4980 t.Fatalf("test1 should have used Dockerfile, output:%s", out) 4981 } 4982 4983 out, _, err = dockerCmdInDir(t, ctx.Dir, "build", "-f", filepath.Join("files", "Dockerfile"), "-t", "test2", ".") 4984 if err != nil { 4985 t.Fatal(err) 4986 } 4987 if !strings.Contains(out, "from files/Dockerfile") { 4988 t.Fatalf("test2 should have used files/Dockerfile, output:%s", out) 4989 } 4990 4991 out, _, err = dockerCmdInDir(t, ctx.Dir, "build", fmt.Sprintf("--file=%s", filepath.Join("files", "dFile")), "-t", "test3", ".") 4992 if err != nil { 4993 t.Fatal(err) 4994 } 4995 if !strings.Contains(out, "from files/dFile") { 4996 t.Fatalf("test3 should have used files/dFile, output:%s", out) 4997 } 4998 4999 out, _, err = dockerCmdInDir(t, ctx.Dir, "build", "--file=dFile", "-t", "test4", ".") 5000 if err != nil { 5001 t.Fatal(err) 5002 } 5003 if !strings.Contains(out, "from dFile") { 5004 t.Fatalf("test4 should have used dFile, output:%s", out) 5005 } 5006 5007 dirWithNoDockerfile, _ := ioutil.TempDir(os.TempDir(), "test5") 5008 nonDockerfileFile := filepath.Join(dirWithNoDockerfile, "notDockerfile") 5009 if _, err = os.Create(nonDockerfileFile); err != nil { 5010 t.Fatal(err) 5011 } 5012 out, _, err = dockerCmdInDir(t, ctx.Dir, "build", fmt.Sprintf("--file=%s", nonDockerfileFile), "-t", "test5", ".") 5013 5014 if err == nil { 5015 t.Fatalf("test5 was supposed to fail to find passwd") 5016 } 5017 5018 if expected := fmt.Sprintf("The Dockerfile (%s) must be within the build context (.)", strings.Replace(nonDockerfileFile, `\`, `\\`, -1)); !strings.Contains(out, expected) { 5019 t.Fatalf("wrong error messsage:%v\nexpected to contain=%v", out, expected) 5020 } 5021 5022 out, _, err = dockerCmdInDir(t, filepath.Join(ctx.Dir, "files"), "build", "-f", filepath.Join("..", "Dockerfile"), "-t", "test6", "..") 5023 if err != nil { 5024 t.Fatalf("test6 failed: %s", err) 5025 } 5026 if !strings.Contains(out, "from Dockerfile") { 5027 t.Fatalf("test6 should have used root Dockerfile, output:%s", out) 5028 } 5029 5030 out, _, err = dockerCmdInDir(t, filepath.Join(ctx.Dir, "files"), "build", "-f", filepath.Join(ctx.Dir, "files", "Dockerfile"), "-t", "test7", "..") 5031 if err != nil { 5032 t.Fatalf("test7 failed: %s", err) 5033 } 5034 if !strings.Contains(out, "from files/Dockerfile") { 5035 t.Fatalf("test7 should have used files Dockerfile, output:%s", out) 5036 } 5037 5038 out, _, err = dockerCmdInDir(t, filepath.Join(ctx.Dir, "files"), "build", "-f", filepath.Join("..", "Dockerfile"), "-t", "test8", ".") 5039 if err == nil || !strings.Contains(out, "must be within the build context") { 5040 t.Fatalf("test8 should have failed with Dockerfile out of context: %s", err) 5041 } 5042 5043 tmpDir := os.TempDir() 5044 out, _, err = dockerCmdInDir(t, tmpDir, "build", "-t", "test9", ctx.Dir) 5045 if err != nil { 5046 t.Fatalf("test9 - failed: %s", err) 5047 } 5048 if !strings.Contains(out, "from Dockerfile") { 5049 t.Fatalf("test9 should have used root Dockerfile, output:%s", out) 5050 } 5051 5052 out, _, err = dockerCmdInDir(t, filepath.Join(ctx.Dir, "files"), "build", "-f", "dFile2", "-t", "test10", ".") 5053 if err != nil { 5054 t.Fatalf("test10 should have worked: %s", err) 5055 } 5056 if !strings.Contains(out, "from files/dFile2") { 5057 t.Fatalf("test10 should have used files/dFile2, output:%s", out) 5058 } 5059 5060 logDone("build - rename dockerfile") 5061 } 5062 5063 func TestBuildFromMixedcaseDockerfile(t *testing.T) { 5064 testRequires(t, UnixCli) // Dockerfile overwrites dockerfile on windows 5065 defer deleteImages("test1") 5066 5067 ctx, err := fakeContext(`FROM busybox 5068 RUN echo from dockerfile`, 5069 map[string]string{ 5070 "dockerfile": "FROM busybox\nRUN echo from dockerfile", 5071 }) 5072 defer ctx.Close() 5073 if err != nil { 5074 t.Fatal(err) 5075 } 5076 5077 out, _, err := dockerCmdInDir(t, ctx.Dir, "build", "-t", "test1", ".") 5078 if err != nil { 5079 t.Fatalf("Failed to build: %s\n%s", out, err) 5080 } 5081 5082 if !strings.Contains(out, "from dockerfile") { 5083 t.Fatalf("Missing proper output: %s", out) 5084 } 5085 5086 logDone("build - mixedcase Dockerfile") 5087 } 5088 5089 func TestBuildWithTwoDockerfiles(t *testing.T) { 5090 testRequires(t, UnixCli) // Dockerfile overwrites dockerfile on windows 5091 defer deleteImages("test1") 5092 5093 ctx, err := fakeContext(`FROM busybox 5094 RUN echo from Dockerfile`, 5095 map[string]string{ 5096 "dockerfile": "FROM busybox\nRUN echo from dockerfile", 5097 }) 5098 defer ctx.Close() 5099 if err != nil { 5100 t.Fatal(err) 5101 } 5102 5103 out, _, err := dockerCmdInDir(t, ctx.Dir, "build", "-t", "test1", ".") 5104 if err != nil { 5105 t.Fatalf("Failed to build: %s\n%s", out, err) 5106 } 5107 5108 if !strings.Contains(out, "from Dockerfile") { 5109 t.Fatalf("Missing proper output: %s", out) 5110 } 5111 5112 logDone("build - two Dockerfiles") 5113 } 5114 5115 func TestBuildFromURLWithF(t *testing.T) { 5116 defer deleteImages("test1") 5117 5118 server, err := fakeStorage(map[string]string{"baz": `FROM busybox 5119 RUN echo from baz 5120 COPY * /tmp/ 5121 RUN find /tmp/`}) 5122 if err != nil { 5123 t.Fatal(err) 5124 } 5125 defer server.Close() 5126 5127 ctx, err := fakeContext(`FROM busybox 5128 RUN echo from Dockerfile`, 5129 map[string]string{}) 5130 defer ctx.Close() 5131 if err != nil { 5132 t.Fatal(err) 5133 } 5134 5135 // Make sure that -f is ignored and that we don't use the Dockerfile 5136 // that's in the current dir 5137 out, _, err := dockerCmdInDir(t, ctx.Dir, "build", "-f", "baz", "-t", "test1", server.URL()+"/baz") 5138 if err != nil { 5139 t.Fatalf("Failed to build: %s\n%s", out, err) 5140 } 5141 5142 if !strings.Contains(out, "from baz") || 5143 strings.Contains(out, "/tmp/baz") || 5144 !strings.Contains(out, "/tmp/Dockerfile") { 5145 t.Fatalf("Missing proper output: %s", out) 5146 } 5147 5148 logDone("build - from URL with -f") 5149 } 5150 5151 func TestBuildFromStdinWithF(t *testing.T) { 5152 defer deleteImages("test1") 5153 5154 ctx, err := fakeContext(`FROM busybox 5155 RUN echo from Dockerfile`, 5156 map[string]string{}) 5157 defer ctx.Close() 5158 if err != nil { 5159 t.Fatal(err) 5160 } 5161 5162 // Make sure that -f is ignored and that we don't use the Dockerfile 5163 // that's in the current dir 5164 dockerCommand := exec.Command(dockerBinary, "build", "-f", "baz", "-t", "test1", "-") 5165 dockerCommand.Dir = ctx.Dir 5166 dockerCommand.Stdin = strings.NewReader(`FROM busybox 5167 RUN echo from baz 5168 COPY * /tmp/ 5169 RUN find /tmp/`) 5170 out, status, err := runCommandWithOutput(dockerCommand) 5171 if err != nil || status != 0 { 5172 t.Fatalf("Error building: %s", err) 5173 } 5174 5175 if !strings.Contains(out, "from baz") || 5176 strings.Contains(out, "/tmp/baz") || 5177 !strings.Contains(out, "/tmp/Dockerfile") { 5178 t.Fatalf("Missing proper output: %s", out) 5179 } 5180 5181 logDone("build - from stdin with -f") 5182 } 5183 5184 func TestBuildFromOfficialNames(t *testing.T) { 5185 name := "testbuildfromofficial" 5186 fromNames := []string{ 5187 "busybox", 5188 "docker.io/busybox", 5189 "index.docker.io/busybox", 5190 "library/busybox", 5191 "docker.io/library/busybox", 5192 "index.docker.io/library/busybox", 5193 } 5194 for idx, fromName := range fromNames { 5195 imgName := fmt.Sprintf("%s%d", name, idx) 5196 _, err := buildImage(imgName, "FROM "+fromName, true) 5197 if err != nil { 5198 t.Errorf("Build failed using FROM %s: %s", fromName, err) 5199 } 5200 deleteImages(imgName) 5201 } 5202 logDone("build - from official names") 5203 } 5204 5205 func TestBuildDockerfileOutsideContext(t *testing.T) { 5206 testRequires(t, UnixCli) // uses os.Symlink: not implemented in windows at the time of writing (go-1.4.2) 5207 5208 name := "testbuilddockerfileoutsidecontext" 5209 tmpdir, err := ioutil.TempDir("", name) 5210 if err != nil { 5211 t.Fatal(err) 5212 } 5213 defer os.RemoveAll(tmpdir) 5214 ctx := filepath.Join(tmpdir, "context") 5215 if err := os.MkdirAll(ctx, 0755); err != nil { 5216 t.Fatal(err) 5217 } 5218 if err := ioutil.WriteFile(filepath.Join(ctx, "Dockerfile"), []byte("FROM scratch\nENV X Y"), 0644); err != nil { 5219 t.Fatal(err) 5220 } 5221 wd, err := os.Getwd() 5222 if err != nil { 5223 t.Fatal(err) 5224 } 5225 defer os.Chdir(wd) 5226 if err := os.Chdir(ctx); err != nil { 5227 t.Fatal(err) 5228 } 5229 if err := ioutil.WriteFile(filepath.Join(tmpdir, "outsideDockerfile"), []byte("FROM scratch\nENV x y"), 0644); err != nil { 5230 t.Fatal(err) 5231 } 5232 if err := os.Symlink(filepath.Join("..", "outsideDockerfile"), filepath.Join(ctx, "dockerfile1")); err != nil { 5233 t.Fatal(err) 5234 } 5235 if err := os.Symlink(filepath.Join(tmpdir, "outsideDockerfile"), filepath.Join(ctx, "dockerfile2")); err != nil { 5236 t.Fatal(err) 5237 } 5238 5239 for _, dockerfilePath := range []string{ 5240 filepath.Join("..", "outsideDockerfile"), 5241 filepath.Join(ctx, "dockerfile1"), 5242 filepath.Join(ctx, "dockerfile2"), 5243 } { 5244 out, _, err := runCommandWithOutput(exec.Command(dockerBinary, "build", "-t", name, "--no-cache", "-f", dockerfilePath, ".")) 5245 if err == nil { 5246 t.Fatalf("Expected error with %s. Out: %s", dockerfilePath, out) 5247 } 5248 if !strings.Contains(out, "must be within the build context") && !strings.Contains(out, "Cannot locate Dockerfile") { 5249 t.Fatalf("Unexpected error with %s. Out: %s", dockerfilePath, out) 5250 } 5251 deleteImages(name) 5252 } 5253 5254 os.Chdir(tmpdir) 5255 5256 // Path to Dockerfile should be resolved relative to working directory, not relative to context. 5257 // There is a Dockerfile in the context, but since there is no Dockerfile in the current directory, the following should fail 5258 out, _, err := runCommandWithOutput(exec.Command(dockerBinary, "build", "-t", name, "--no-cache", "-f", "Dockerfile", ctx)) 5259 if err == nil { 5260 t.Fatalf("Expected error. Out: %s", out) 5261 } 5262 deleteImages(name) 5263 5264 logDone("build - Dockerfile outside context") 5265 } 5266 5267 func TestBuildSpaces(t *testing.T) { 5268 // Test to make sure that leading/trailing spaces on a command 5269 // doesn't change the error msg we get 5270 var ( 5271 err1 error 5272 err2 error 5273 ) 5274 5275 name := "testspaces" 5276 defer deleteImages(name) 5277 ctx, err := fakeContext("FROM busybox\nCOPY\n", 5278 map[string]string{ 5279 "Dockerfile": "FROM busybox\nCOPY\n", 5280 }) 5281 if err != nil { 5282 t.Fatal(err) 5283 } 5284 defer ctx.Close() 5285 5286 if _, err1 = buildImageFromContext(name, ctx, false); err1 == nil { 5287 t.Fatal("Build 1 was supposed to fail, but didn't") 5288 } 5289 5290 ctx.Add("Dockerfile", "FROM busybox\nCOPY ") 5291 if _, err2 = buildImageFromContext(name, ctx, false); err2 == nil { 5292 t.Fatal("Build 2 was supposed to fail, but didn't") 5293 } 5294 5295 removeLogTimestamps := func(s string) string { 5296 return regexp.MustCompile(`time="(.*?)"`).ReplaceAllString(s, `time=[TIMESTAMP]`) 5297 } 5298 5299 // Skip over the times 5300 e1 := removeLogTimestamps(err1.Error()) 5301 e2 := removeLogTimestamps(err2.Error()) 5302 5303 // Ignore whitespace since that's what were verifying doesn't change stuff 5304 if strings.Replace(e1, " ", "", -1) != strings.Replace(e2, " ", "", -1) { 5305 t.Fatalf("Build 2's error wasn't the same as build 1's\n1:%s\n2:%s", err1, err2) 5306 } 5307 5308 ctx.Add("Dockerfile", "FROM busybox\n COPY") 5309 if _, err2 = buildImageFromContext(name, ctx, false); err2 == nil { 5310 t.Fatal("Build 3 was supposed to fail, but didn't") 5311 } 5312 5313 // Skip over the times 5314 e1 = removeLogTimestamps(err1.Error()) 5315 e2 = removeLogTimestamps(err2.Error()) 5316 5317 // Ignore whitespace since that's what were verifying doesn't change stuff 5318 if strings.Replace(e1, " ", "", -1) != strings.Replace(e2, " ", "", -1) { 5319 t.Fatalf("Build 3's error wasn't the same as build 1's\n1:%s\n3:%s", err1, err2) 5320 } 5321 5322 ctx.Add("Dockerfile", "FROM busybox\n COPY ") 5323 if _, err2 = buildImageFromContext(name, ctx, false); err2 == nil { 5324 t.Fatal("Build 4 was supposed to fail, but didn't") 5325 } 5326 5327 // Skip over the times 5328 e1 = removeLogTimestamps(err1.Error()) 5329 e2 = removeLogTimestamps(err2.Error()) 5330 5331 // Ignore whitespace since that's what were verifying doesn't change stuff 5332 if strings.Replace(e1, " ", "", -1) != strings.Replace(e2, " ", "", -1) { 5333 t.Fatalf("Build 4's error wasn't the same as build 1's\n1:%s\n4:%s", err1, err2) 5334 } 5335 5336 logDone("build - test spaces") 5337 } 5338 5339 func TestBuildSpacesWithQuotes(t *testing.T) { 5340 // Test to make sure that spaces in quotes aren't lost 5341 name := "testspacesquotes" 5342 defer deleteImages(name) 5343 5344 dockerfile := `FROM busybox 5345 RUN echo " \ 5346 foo "` 5347 5348 _, out, err := buildImageWithOut(name, dockerfile, false) 5349 if err != nil { 5350 t.Fatal("Build failed:", err) 5351 } 5352 5353 expecting := "\n foo \n" 5354 if !strings.Contains(out, expecting) { 5355 t.Fatalf("Bad output: %q expecting to contian %q", out, expecting) 5356 } 5357 5358 logDone("build - test spaces with quotes") 5359 } 5360 5361 // #4393 5362 func TestBuildVolumeFileExistsinContainer(t *testing.T) { 5363 buildCmd := exec.Command(dockerBinary, "build", "-t", "docker-test-errcreatevolumewithfile", "-") 5364 buildCmd.Stdin = strings.NewReader(` 5365 FROM busybox 5366 RUN touch /foo 5367 VOLUME /foo 5368 `) 5369 5370 out, _, err := runCommandWithOutput(buildCmd) 5371 if err == nil || !strings.Contains(out, "file exists") { 5372 t.Fatalf("expected build to fail when file exists in container at requested volume path") 5373 } 5374 5375 logDone("build - errors when volume is specified where a file exists") 5376 } 5377 5378 func TestBuildMissingArgs(t *testing.T) { 5379 // Test to make sure that all Dockerfile commands (except the ones listed 5380 // in skipCmds) will generate an error if no args are provided. 5381 // Note: INSERT is deprecated so we exclude it because of that. 5382 skipCmds := map[string]struct{}{ 5383 "CMD": {}, 5384 "RUN": {}, 5385 "ENTRYPOINT": {}, 5386 "INSERT": {}, 5387 } 5388 5389 defer deleteAllContainers() 5390 5391 for cmd := range command.Commands { 5392 cmd = strings.ToUpper(cmd) 5393 if _, ok := skipCmds[cmd]; ok { 5394 continue 5395 } 5396 5397 var dockerfile string 5398 if cmd == "FROM" { 5399 dockerfile = cmd 5400 } else { 5401 // Add FROM to make sure we don't complain about it missing 5402 dockerfile = "FROM busybox\n" + cmd 5403 } 5404 5405 ctx, err := fakeContext(dockerfile, map[string]string{}) 5406 if err != nil { 5407 t.Fatal(err) 5408 } 5409 defer ctx.Close() 5410 var out string 5411 if out, err = buildImageFromContext("args", ctx, true); err == nil { 5412 t.Fatalf("%s was supposed to fail. Out:%s", cmd, out) 5413 } 5414 if !strings.Contains(err.Error(), cmd+" requires") { 5415 t.Fatalf("%s returned the wrong type of error:%s", cmd, err) 5416 } 5417 } 5418 5419 logDone("build - verify missing args") 5420 } 5421 5422 func TestBuildEmptyScratch(t *testing.T) { 5423 defer deleteImages("sc") 5424 _, out, err := buildImageWithOut("sc", "FROM scratch", true) 5425 if err == nil { 5426 t.Fatalf("Build was supposed to fail") 5427 } 5428 if !strings.Contains(out, "No image was generated") { 5429 t.Fatalf("Wrong error message: %v", out) 5430 } 5431 logDone("build - empty scratch Dockerfile") 5432 } 5433 5434 func TestBuildDotDotFile(t *testing.T) { 5435 defer deleteImages("sc") 5436 ctx, err := fakeContext("FROM busybox\n", 5437 map[string]string{ 5438 "..gitme": "", 5439 }) 5440 if err != nil { 5441 t.Fatal(err) 5442 } 5443 defer ctx.Close() 5444 5445 if _, err = buildImageFromContext("sc", ctx, false); err != nil { 5446 t.Fatalf("Build was supposed to work: %s", err) 5447 } 5448 logDone("build - ..file") 5449 } 5450 5451 func TestBuildNotVerbose(t *testing.T) { 5452 defer deleteAllContainers() 5453 defer deleteImages("verbose") 5454 5455 ctx, err := fakeContext("FROM busybox\nENV abc=hi\nRUN echo $abc there", map[string]string{}) 5456 if err != nil { 5457 t.Fatal(err) 5458 } 5459 defer ctx.Close() 5460 5461 // First do it w/verbose - baseline 5462 buildCmd := exec.Command(dockerBinary, "build", "--no-cache", "-t", "verbose", ".") 5463 buildCmd.Dir = ctx.Dir 5464 out, _, err := runCommandWithOutput(buildCmd) 5465 if err != nil { 5466 t.Fatalf("failed to build the image w/o -q: %s, %v", out, err) 5467 } 5468 if !strings.Contains(out, "hi there") { 5469 t.Fatalf("missing output:%s\n", out) 5470 } 5471 5472 // Now do it w/o verbose 5473 buildCmd = exec.Command(dockerBinary, "build", "--no-cache", "-q", "-t", "verbose", ".") 5474 buildCmd.Dir = ctx.Dir 5475 out, _, err = runCommandWithOutput(buildCmd) 5476 if err != nil { 5477 t.Fatalf("failed to build the image w/ -q: %s, %v", out, err) 5478 } 5479 if strings.Contains(out, "hi there") { 5480 t.Fatalf("Bad output, should not contain 'hi there':%s", out) 5481 } 5482 5483 logDone("build - not verbose") 5484 } 5485 5486 func TestBuildRUNoneJSON(t *testing.T) { 5487 name := "testbuildrunonejson" 5488 5489 defer deleteAllContainers() 5490 defer deleteImages(name) 5491 5492 ctx, err := fakeContext(`FROM hello-world:frozen 5493 RUN [ "/hello" ]`, map[string]string{}) 5494 if err != nil { 5495 t.Fatal(err) 5496 } 5497 defer ctx.Close() 5498 5499 buildCmd := exec.Command(dockerBinary, "build", "--no-cache", "-t", name, ".") 5500 buildCmd.Dir = ctx.Dir 5501 out, _, err := runCommandWithOutput(buildCmd) 5502 if err != nil { 5503 t.Fatalf("failed to build the image: %s, %v", out, err) 5504 } 5505 5506 if !strings.Contains(out, "Hello from Docker") { 5507 t.Fatalf("bad output: %s", out) 5508 } 5509 5510 logDone("build - RUN with one JSON arg") 5511 } 5512 5513 func TestBuildResourceConstraintsAreUsed(t *testing.T) { 5514 name := "testbuildresourceconstraints" 5515 defer deleteAllContainers() 5516 defer deleteImages(name) 5517 5518 ctx, err := fakeContext(` 5519 FROM hello-world:frozen 5520 RUN ["/hello"] 5521 `, map[string]string{}) 5522 if err != nil { 5523 t.Fatal(err) 5524 } 5525 5526 cmd := exec.Command(dockerBinary, "build", "--rm=false", "--memory=64m", "--memory-swap=-1", "--cpuset-cpus=1", "--cpu-shares=100", "-t", name, ".") 5527 cmd.Dir = ctx.Dir 5528 5529 out, _, err := runCommandWithOutput(cmd) 5530 if err != nil { 5531 t.Fatal(err, out) 5532 } 5533 out, _, err = dockerCmd(t, "ps", "-lq") 5534 if err != nil { 5535 t.Fatal(err, out) 5536 } 5537 5538 cID := stripTrailingCharacters(out) 5539 5540 type hostConfig struct { 5541 Memory float64 // Use float64 here since the json decoder sees it that way 5542 MemorySwap int 5543 CpusetCpus string 5544 CpuShares int 5545 } 5546 5547 cfg, err := inspectFieldJSON(cID, "HostConfig") 5548 if err != nil { 5549 t.Fatal(err) 5550 } 5551 5552 var c1 hostConfig 5553 if err := json.Unmarshal([]byte(cfg), &c1); err != nil { 5554 t.Fatal(err, cfg) 5555 } 5556 mem := int64(c1.Memory) 5557 if mem != 67108864 || c1.MemorySwap != -1 || c1.CpusetCpus != "1" || c1.CpuShares != 100 { 5558 t.Fatalf("resource constraints not set properly:\nMemory: %d, MemSwap: %d, CpusetCpus: %s, CpuShares: %d", 5559 mem, c1.MemorySwap, c1.CpusetCpus, c1.CpuShares) 5560 } 5561 5562 // Make sure constraints aren't saved to image 5563 _, _, err = dockerCmd(t, "run", "--name=test", name) 5564 if err != nil { 5565 t.Fatal(err) 5566 } 5567 cfg, err = inspectFieldJSON("test", "HostConfig") 5568 if err != nil { 5569 t.Fatal(err) 5570 } 5571 var c2 hostConfig 5572 if err := json.Unmarshal([]byte(cfg), &c2); err != nil { 5573 t.Fatal(err, cfg) 5574 } 5575 mem = int64(c2.Memory) 5576 if mem == 67108864 || c2.MemorySwap == -1 || c2.CpusetCpus == "1" || c2.CpuShares == 100 { 5577 t.Fatalf("resource constraints leaked from build:\nMemory: %d, MemSwap: %d, CpusetCpus: %s, CpuShares: %d", 5578 mem, c2.MemorySwap, c2.CpusetCpus, c2.CpuShares) 5579 } 5580 5581 logDone("build - resource constraints applied") 5582 } 5583 5584 func TestBuildEmptyStringVolume(t *testing.T) { 5585 name := "testbuildemptystringvolume" 5586 defer deleteImages(name) 5587 5588 _, err := buildImage(name, ` 5589 FROM busybox 5590 ENV foo="" 5591 VOLUME $foo 5592 `, false) 5593 if err == nil { 5594 t.Fatal("Should have failed to build") 5595 } 5596 5597 logDone("build - empty string volume") 5598 }