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