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