2014-02-25 20:17:48 +04:00
package main
import (
2014-07-21 23:10:47 +04:00
"archive/tar"
2014-11-13 06:14:15 +03:00
"bytes"
2014-10-25 22:29:18 +04:00
"encoding/json"
2014-02-25 20:17:48 +04:00
"fmt"
2014-07-21 23:10:47 +04:00
"io/ioutil"
2014-05-13 22:49:12 +04:00
"os"
2014-02-25 20:17:48 +04:00
"os/exec"
"path/filepath"
2014-12-04 04:52:06 +03:00
"reflect"
2014-10-14 00:14:35 +04:00
"regexp"
2015-02-18 10:20:20 +03:00
"runtime"
2014-11-13 06:14:15 +03:00
"strconv"
2014-05-13 22:49:12 +04:00
"strings"
2014-02-25 20:17:48 +04:00
"testing"
2014-11-13 06:14:15 +03:00
"text/template"
2014-05-23 02:12:41 +04:00
"time"
2014-05-10 02:26:41 +04:00
2015-02-12 08:18:48 +03:00
"github.com/docker/docker/builder/command"
2014-09-30 10:23:36 +04:00
"github.com/docker/docker/pkg/archive"
2014-02-25 20:17:48 +04:00
)
2015-01-09 04:00:00 +03:00
func TestBuildJSONEmptyRun ( t * testing . T ) {
name := "testbuildjsonemptyrun"
defer deleteImages ( name )
_ , err := buildImage (
name ,
`
FROM busybox
RUN [ ]
` ,
true )
if err != nil {
t . Fatal ( "error when dealing with a RUN statement with empty JSON array" )
}
logDone ( "build - RUN with an empty array should not panic" )
}
2015-01-08 22:30:08 +03:00
func TestBuildEmptyWhitespace ( t * testing . T ) {
name := "testbuildemptywhitespace"
defer deleteImages ( name )
_ , err := buildImage (
name ,
`
FROM busybox
2015-02-04 20:34:25 +03:00
COPY
2015-01-08 22:30:08 +03:00
quux \
bar
` ,
true )
if err == nil {
2015-02-04 20:34:25 +03:00
t . Fatal ( "no error when dealing with a COPY statement with no content on the same line" )
2015-01-08 22:30:08 +03:00
}
logDone ( "build - statements with whitespace and no content should generate a parse error" )
}
2014-10-28 00:15:28 +03:00
func TestBuildShCmdJSONEntrypoint ( t * testing . T ) {
name := "testbuildshcmdjsonentrypoint"
defer deleteImages ( name )
_ , err := buildImage (
name ,
`
FROM busybox
ENTRYPOINT [ "/bin/echo" ]
CMD echo test
` ,
true )
if err != nil {
t . Fatal ( err )
}
out , _ , err := runCommandWithOutput (
exec . Command (
dockerBinary ,
"run" ,
2014-11-17 19:05:49 +03:00
"--rm" ,
2014-10-28 00:15:28 +03:00
name ) )
if err != nil {
t . Fatal ( err )
}
if strings . TrimSpace ( out ) != "/bin/sh -c echo test" {
t . Fatal ( "CMD did not contain /bin/sh -c" )
}
logDone ( "build - CMD should always contain /bin/sh -c when specified without JSON" )
}
2014-10-25 22:29:18 +04:00
func TestBuildEnvironmentReplacementUser ( t * testing . T ) {
name := "testbuildenvironmentreplacement"
defer deleteImages ( name )
_ , err := buildImage ( name , `
FROM scratch
ENV user foo
USER $ { user }
` , true )
if err != nil {
t . Fatal ( err )
}
res , err := inspectFieldJSON ( name , "Config.User" )
if err != nil {
t . Fatal ( err )
}
if res != ` "foo" ` {
t . Fatal ( "User foo from environment not in Config.User on image" )
}
logDone ( "build - user environment replacement" )
}
func TestBuildEnvironmentReplacementVolume ( t * testing . T ) {
name := "testbuildenvironmentreplacement"
defer deleteImages ( name )
_ , err := buildImage ( name , `
FROM scratch
ENV volume / quux
VOLUME $ { volume }
` , true )
if err != nil {
t . Fatal ( err )
}
res , err := inspectFieldJSON ( name , "Config.Volumes" )
if err != nil {
t . Fatal ( err )
}
var volumes map [ string ] interface { }
if err := json . Unmarshal ( [ ] byte ( res ) , & volumes ) ; err != nil {
t . Fatal ( err )
}
if _ , ok := volumes [ "/quux" ] ; ! ok {
t . Fatal ( "Volume /quux from environment not in Config.Volumes on image" )
}
logDone ( "build - volume environment replacement" )
}
func TestBuildEnvironmentReplacementExpose ( t * testing . T ) {
name := "testbuildenvironmentreplacement"
defer deleteImages ( name )
_ , err := buildImage ( name , `
FROM scratch
ENV port 80
EXPOSE $ { port }
` , true )
if err != nil {
t . Fatal ( err )
}
res , err := inspectFieldJSON ( name , "Config.ExposedPorts" )
if err != nil {
t . Fatal ( err )
}
var exposedPorts map [ string ] interface { }
if err := json . Unmarshal ( [ ] byte ( res ) , & exposedPorts ) ; err != nil {
t . Fatal ( err )
}
if _ , ok := exposedPorts [ "80/tcp" ] ; ! ok {
t . Fatal ( "Exposed port 80 from environment not in Config.ExposedPorts on image" )
}
logDone ( "build - expose environment replacement" )
}
func TestBuildEnvironmentReplacementWorkdir ( t * testing . T ) {
name := "testbuildenvironmentreplacement"
defer deleteImages ( name )
_ , err := buildImage ( name , `
FROM busybox
ENV MYWORKDIR / work
RUN mkdir $ { MYWORKDIR }
WORKDIR $ { MYWORKDIR }
` , true )
if err != nil {
t . Fatal ( err )
}
logDone ( "build - workdir environment replacement" )
}
func TestBuildEnvironmentReplacementAddCopy ( t * testing . T ) {
name := "testbuildenvironmentreplacement"
defer deleteImages ( name )
ctx , err := fakeContext ( `
FROM scratch
ENV baz foo
ENV quux bar
ENV dot .
ADD $ { baz } $ { dot }
COPY $ { quux } $ { dot }
` ,
map [ string ] string {
"foo" : "test1" ,
"bar" : "test2" ,
} )
if err != nil {
t . Fatal ( err )
}
2014-11-20 20:38:41 +03:00
defer ctx . Close ( )
2014-10-25 22:29:18 +04:00
if _ , err := buildImageFromContext ( name , ctx , true ) ; err != nil {
t . Fatal ( err )
}
logDone ( "build - add/copy environment replacement" )
}
func TestBuildEnvironmentReplacementEnv ( t * testing . T ) {
name := "testbuildenvironmentreplacement"
defer deleteImages ( name )
_ , err := buildImage ( name ,
`
FROM scratch
ENV foo foo
ENV bar $ { foo }
` , true )
if err != nil {
t . Fatal ( err )
}
res , err := inspectFieldJSON ( name , "Config.Env" )
if err != nil {
t . Fatal ( err )
}
envResult := [ ] string { }
if err = unmarshalJSON ( [ ] byte ( res ) , & envResult ) ; err != nil {
t . Fatal ( err )
}
found := false
for _ , env := range envResult {
parts := strings . SplitN ( env , "=" , 2 )
if parts [ 0 ] == "bar" {
found = true
if parts [ 1 ] != "foo" {
2014-11-05 19:26:22 +03:00
t . Fatalf ( "Could not find replaced var for env `bar`: got %q instead of `foo`" , parts [ 1 ] )
2014-10-25 22:29:18 +04:00
}
}
}
if ! found {
t . Fatal ( "Never found the `bar` env variable" )
}
logDone ( "build - env environment replacement" )
}
2014-10-25 21:58:57 +04:00
func TestBuildHandleEscapes ( t * testing . T ) {
name := "testbuildhandleescapes"
defer deleteImages ( name )
_ , err := buildImage ( name ,
`
FROM scratch
ENV FOO bar
VOLUME $ { FOO }
` , true )
if err != nil {
t . Fatal ( err )
}
var result map [ string ] map [ string ] struct { }
res , err := inspectFieldJSON ( name , "Config.Volumes" )
if err != nil {
t . Fatal ( err )
}
if err = unmarshalJSON ( [ ] byte ( res ) , & result ) ; err != nil {
t . Fatal ( err )
}
if _ , ok := result [ "bar" ] ; ! ok {
t . Fatal ( "Could not find volume bar set from env foo in volumes table" )
}
2014-11-17 19:05:49 +03:00
deleteImages ( name )
2014-10-25 21:58:57 +04:00
_ , err = buildImage ( name ,
`
FROM scratch
ENV FOO bar
VOLUME \ $ { FOO }
` , true )
if err != nil {
t . Fatal ( err )
}
res , err = inspectFieldJSON ( name , "Config.Volumes" )
if err != nil {
t . Fatal ( err )
}
if err = unmarshalJSON ( [ ] byte ( res ) , & result ) ; err != nil {
t . Fatal ( err )
}
if _ , ok := result [ "${FOO}" ] ; ! ok {
t . Fatal ( "Could not find volume ${FOO} set from env foo in volumes table" )
}
2014-11-17 19:05:49 +03:00
deleteImages ( name )
2014-10-25 21:58:57 +04:00
// this test in particular provides *7* backslashes and expects 6 to come back.
// Like above, the first escape is swallowed and the rest are treated as
// literals, this one is just less obvious because of all the character noise.
_ , err = buildImage ( name ,
`
FROM scratch
ENV FOO bar
VOLUME \ \ \ \ \ \ \ $ { FOO }
` , true )
if err != nil {
t . Fatal ( err )
}
res , err = inspectFieldJSON ( name , "Config.Volumes" )
if err != nil {
t . Fatal ( err )
}
if err = unmarshalJSON ( [ ] byte ( res ) , & result ) ; err != nil {
t . Fatal ( err )
}
if _ , ok := result [ ` \\\\\\$ { FOO} ` ] ; ! ok {
t . Fatal ( ` Could not find volume \\\\\\$ { FOO} set from env foo in volumes table ` )
}
logDone ( "build - handle escapes" )
}
2014-10-21 23:26:20 +04:00
func TestBuildOnBuildLowercase ( t * testing . T ) {
name := "testbuildonbuildlowercase"
name2 := "testbuildonbuildlowercase2"
defer deleteImages ( name , name2 )
_ , err := buildImage ( name ,
`
FROM busybox
onbuild run echo quux
` , true )
if err != nil {
t . Fatal ( err )
}
_ , out , err := buildImageWithOut ( name2 , fmt . Sprintf ( `
FROM % s
` , name ) , true )
if err != nil {
t . Fatal ( err )
}
if ! strings . Contains ( out , "quux" ) {
t . Fatalf ( "Did not receive the expected echo text, got %s" , out )
}
if strings . Contains ( out , "ONBUILD ONBUILD" ) {
t . Fatalf ( "Got an ONBUILD ONBUILD error with no error: got %s" , out )
}
logDone ( "build - handle case-insensitive onbuild statement" )
}
2014-10-17 23:15:07 +04:00
func TestBuildEnvEscapes ( t * testing . T ) {
name := "testbuildenvescapes"
defer deleteImages ( name )
2014-11-17 19:05:49 +03:00
defer deleteAllContainers ( )
2014-10-17 23:15:07 +04:00
_ , err := buildImage ( name ,
`
FROM busybox
ENV TEST foo
CMD echo \ $
` ,
true )
out , _ , err := runCommandWithOutput ( exec . Command ( dockerBinary , "run" , "-t" , name ) )
if err != nil {
t . Fatal ( err )
}
if strings . TrimSpace ( out ) != "$" {
t . Fatalf ( "Env TEST was not overwritten with bar when foo was supplied to dockerfile: was %q" , strings . TrimSpace ( out ) )
}
logDone ( "build - env should handle \\$ properly" )
}
func TestBuildEnvOverwrite ( t * testing . T ) {
name := "testbuildenvoverwrite"
defer deleteImages ( name )
2014-11-17 19:05:49 +03:00
defer deleteAllContainers ( )
2014-10-17 23:15:07 +04:00
_ , err := buildImage ( name ,
`
FROM busybox
ENV TEST foo
2014-10-25 22:29:18 +04:00
CMD echo $ { TEST }
2014-10-17 23:15:07 +04:00
` ,
true )
if err != nil {
t . Fatal ( err )
}
out , _ , err := runCommandWithOutput ( exec . Command ( dockerBinary , "run" , "-e" , "TEST=bar" , "-t" , name ) )
if err != nil {
t . Fatal ( err )
}
if strings . TrimSpace ( out ) != "bar" {
t . Fatalf ( "Env TEST was not overwritten with bar when foo was supplied to dockerfile: was %q" , strings . TrimSpace ( out ) )
}
logDone ( "build - env should overwrite builder ENV during run" )
}
2014-10-14 00:14:35 +04:00
func TestBuildOnBuildForbiddenMaintainerInSourceImage ( t * testing . T ) {
name := "testbuildonbuildforbiddenmaintainerinsourceimage"
2014-11-17 19:05:49 +03:00
defer deleteImages ( "onbuild" )
2014-10-14 00:14:35 +04:00
defer deleteImages ( name )
2014-11-17 19:05:49 +03:00
defer deleteAllContainers ( )
2014-10-14 00:14:35 +04:00
createCmd := exec . Command ( dockerBinary , "create" , "busybox" , "true" )
out , _ , _ , err := runCommandWithStdoutStderr ( createCmd )
2014-10-15 00:51:12 +04:00
if err != nil {
t . Fatal ( out , err )
}
2014-10-14 00:14:35 +04:00
cleanedContainerID := stripTrailingCharacters ( out )
commitCmd := exec . Command ( dockerBinary , "commit" , "--run" , "{\"OnBuild\":[\"MAINTAINER docker.io\"]}" , cleanedContainerID , "onbuild" )
if _ , err := runCommand ( commitCmd ) ; err != nil {
t . Fatal ( err )
}
_ , err = buildImage ( name ,
` FROM onbuild ` ,
true )
if err != nil {
if ! strings . Contains ( err . Error ( ) , "maintainer isn't allowed as an ONBUILD trigger" ) {
t . Fatalf ( "Wrong error %v, must be about MAINTAINER and ONBUILD in source image" , err )
}
} else {
t . Fatal ( "Error must not be nil" )
}
logDone ( "build - onbuild forbidden maintainer in source image" )
}
func TestBuildOnBuildForbiddenFromInSourceImage ( t * testing . T ) {
name := "testbuildonbuildforbiddenfrominsourceimage"
2014-11-17 19:05:49 +03:00
defer deleteImages ( "onbuild" )
2014-10-14 00:14:35 +04:00
defer deleteImages ( name )
2014-11-17 19:05:49 +03:00
defer deleteAllContainers ( )
2014-10-14 00:14:35 +04:00
createCmd := exec . Command ( dockerBinary , "create" , "busybox" , "true" )
out , _ , _ , err := runCommandWithStdoutStderr ( createCmd )
2014-10-15 00:51:12 +04:00
if err != nil {
t . Fatal ( out , err )
}
2014-10-14 00:14:35 +04:00
cleanedContainerID := stripTrailingCharacters ( out )
commitCmd := exec . Command ( dockerBinary , "commit" , "--run" , "{\"OnBuild\":[\"FROM busybox\"]}" , cleanedContainerID , "onbuild" )
if _ , err := runCommand ( commitCmd ) ; err != nil {
t . Fatal ( err )
}
_ , err = buildImage ( name ,
` FROM onbuild ` ,
true )
if err != nil {
if ! strings . Contains ( err . Error ( ) , "from isn't allowed as an ONBUILD trigger" ) {
t . Fatalf ( "Wrong error %v, must be about FROM and ONBUILD in source image" , err )
}
} else {
t . Fatal ( "Error must not be nil" )
}
logDone ( "build - onbuild forbidden from in source image" )
}
func TestBuildOnBuildForbiddenChainedInSourceImage ( t * testing . T ) {
name := "testbuildonbuildforbiddenchainedinsourceimage"
2014-11-17 19:05:49 +03:00
defer deleteImages ( "onbuild" )
2014-10-14 00:14:35 +04:00
defer deleteImages ( name )
2014-11-17 19:05:49 +03:00
defer deleteAllContainers ( )
2014-10-14 00:14:35 +04:00
createCmd := exec . Command ( dockerBinary , "create" , "busybox" , "true" )
out , _ , _ , err := runCommandWithStdoutStderr ( createCmd )
2014-10-15 00:51:12 +04:00
if err != nil {
t . Fatal ( out , err )
}
2014-10-14 00:14:35 +04:00
cleanedContainerID := stripTrailingCharacters ( out )
commitCmd := exec . Command ( dockerBinary , "commit" , "--run" , "{\"OnBuild\":[\"ONBUILD RUN ls\"]}" , cleanedContainerID , "onbuild" )
if _ , err := runCommand ( commitCmd ) ; err != nil {
t . Fatal ( err )
}
_ , err = buildImage ( name ,
` FROM onbuild ` ,
true )
if err != nil {
if ! strings . Contains ( err . Error ( ) , "Chaining ONBUILD via `ONBUILD ONBUILD` isn't allowed" ) {
t . Fatalf ( "Wrong error %v, must be about chaining ONBUILD in source image" , err )
}
} else {
t . Fatal ( "Error must not be nil" )
}
logDone ( "build - onbuild forbidden chained in source image" )
}
func TestBuildOnBuildCmdEntrypointJSON ( t * testing . T ) {
name1 := "onbuildcmd"
name2 := "onbuildgenerated"
defer deleteImages ( name2 )
defer deleteImages ( name1 )
2014-11-17 19:05:49 +03:00
defer deleteAllContainers ( )
2014-10-14 00:14:35 +04:00
_ , err := buildImage ( name1 , `
FROM busybox
ONBUILD CMD [ "hello world" ]
ONBUILD ENTRYPOINT [ "echo" ]
ONBUILD RUN [ "true" ] ` ,
false )
if err != nil {
t . Fatal ( err )
}
_ , err = buildImage ( name2 , fmt . Sprintf ( ` FROM %s ` , name1 ) , false )
if err != nil {
t . Fatal ( err )
}
out , _ , err := runCommandWithOutput ( exec . Command ( dockerBinary , "run" , "-t" , name2 ) )
if err != nil {
t . Fatal ( err )
}
if ! regexp . MustCompile ( ` (?m)^hello world ` ) . MatchString ( out ) {
t . Fatal ( "did not get echo output from onbuild" , out )
}
logDone ( "build - onbuild with json entrypoint/cmd" )
}
func TestBuildOnBuildEntrypointJSON ( t * testing . T ) {
name1 := "onbuildcmd"
name2 := "onbuildgenerated"
defer deleteImages ( name2 )
defer deleteImages ( name1 )
2014-11-17 19:05:49 +03:00
defer deleteAllContainers ( )
2014-10-14 00:14:35 +04:00
_ , err := buildImage ( name1 , `
FROM busybox
ONBUILD ENTRYPOINT [ "echo" ] ` ,
false )
if err != nil {
t . Fatal ( err )
}
_ , err = buildImage ( name2 , fmt . Sprintf ( "FROM %s\nCMD [\"hello world\"]\n" , name1 ) , false )
if err != nil {
t . Fatal ( err )
}
out , _ , err := runCommandWithOutput ( exec . Command ( dockerBinary , "run" , "-t" , name2 ) )
if err != nil {
t . Fatal ( err )
}
if ! regexp . MustCompile ( ` (?m)^hello world ` ) . MatchString ( out ) {
t . Fatal ( "got malformed output from onbuild" , out )
}
logDone ( "build - onbuild with json entrypoint" )
}
2014-05-21 01:29:19 +04:00
func TestBuildCacheADD ( t * testing . T ) {
2014-08-18 14:13:43 +04:00
name := "testbuildtwoimageswithadd"
defer deleteImages ( name )
server , err := fakeStorage ( map [ string ] string {
"robots.txt" : "hello" ,
"index.html" : "world" ,
} )
if err != nil {
t . Fatal ( err )
2014-05-21 01:29:19 +04:00
}
2014-08-18 14:13:43 +04:00
defer server . Close ( )
2015-02-19 13:01:27 +03:00
2014-08-18 14:13:43 +04:00
if _ , err := buildImage ( name ,
fmt . Sprintf ( ` FROM scratch
2015-02-19 13:01:27 +03:00
ADD % s / robots . txt / ` , server . URL ( ) ) ,
2014-08-18 14:13:43 +04:00
true ) ; err != nil {
t . Fatal ( err )
}
2014-11-17 19:05:49 +03:00
if err != nil {
t . Fatal ( err )
}
deleteImages ( name )
2014-10-06 21:04:10 +04:00
_ , out , err := buildImageWithOut ( name ,
2014-08-18 14:13:43 +04:00
fmt . Sprintf ( ` FROM scratch
2015-02-19 13:01:27 +03:00
ADD % s / index . html / ` , server . URL ( ) ) ,
2014-08-18 14:13:43 +04:00
true )
if err != nil {
t . Fatal ( err )
2014-05-21 01:29:19 +04:00
}
if strings . Contains ( out , "Using cache" ) {
t . Fatal ( "2nd build used cache on ADD, it shouldn't" )
}
2014-08-18 14:13:43 +04:00
logDone ( "build - build two images with remote ADD" )
2014-05-21 01:29:19 +04:00
}
2015-03-04 20:14:58 +03:00
func TestBuildLastModified ( t * testing . T ) {
name := "testbuildlastmodified"
defer deleteImages ( name )
server , err := fakeStorage ( map [ string ] string {
"file" : "hello" ,
} )
if err != nil {
t . Fatal ( err )
}
defer server . Close ( )
var out , out2 string
dFmt := ` FROM busybox
ADD % s / file /
RUN ls - le / file `
2015-03-10 02:56:51 +03:00
dockerfile := fmt . Sprintf ( dFmt , server . URL ( ) )
2015-03-04 20:14:58 +03:00
if _ , out , err = buildImageWithOut ( name , dockerfile , false ) ; err != nil {
t . Fatal ( err )
}
originMTime := regexp . MustCompile ( ` root.*/file.*\n ` ) . FindString ( out )
// Make sure our regexp is correct
if strings . Index ( originMTime , "/file" ) < 0 {
t . Fatalf ( "Missing ls info on 'file':\n%s" , out )
}
// Build it again and make sure the mtime of the file didn't change.
// Wait a few seconds to make sure the time changed enough to notice
time . Sleep ( 2 * time . Second )
if _ , out2 , err = buildImageWithOut ( name , dockerfile , false ) ; err != nil {
t . Fatal ( err )
}
newMTime := regexp . MustCompile ( ` root.*/file.*\n ` ) . FindString ( out2 )
if newMTime != originMTime {
t . Fatalf ( "MTime changed:\nOrigin:%s\nNew:%s" , originMTime , newMTime )
}
// Now 'touch' the file and make sure the timestamp DID change this time
// Create a new fakeStorage instead of just using Add() to help windows
server , err = fakeStorage ( map [ string ] string {
"file" : "hello" ,
} )
if err != nil {
t . Fatal ( err )
}
defer server . Close ( )
2015-03-10 02:56:51 +03:00
dockerfile = fmt . Sprintf ( dFmt , server . URL ( ) )
2015-03-04 20:14:58 +03:00
if _ , out2 , err = buildImageWithOut ( name , dockerfile , false ) ; err != nil {
t . Fatal ( err )
}
newMTime = regexp . MustCompile ( ` root.*/file.*\n ` ) . FindString ( out2 )
if newMTime == originMTime {
t . Fatalf ( "MTime didn't change:\nOrigin:%s\nNew:%s" , originMTime , newMTime )
}
logDone ( "build - use Last-Modified header" )
}
2014-02-25 20:17:48 +04:00
func TestBuildSixtySteps ( t * testing . T ) {
2014-09-22 18:18:19 +04:00
name := "foobuildsixtysteps"
defer deleteImages ( name )
ctx , err := fakeContext ( "FROM scratch\n" + strings . Repeat ( "ADD foo /\n" , 60 ) ,
map [ string ] string {
"foo" : "test1" ,
} )
if err != nil {
t . Fatal ( err )
}
2014-11-20 20:38:41 +03:00
defer ctx . Close ( )
2014-09-22 18:18:19 +04:00
if _ , err := buildImageFromContext ( name , ctx , true ) ; err != nil {
t . Fatal ( err )
2014-02-25 20:17:48 +04:00
}
logDone ( "build - build an image with sixty build steps" )
}
2014-09-19 16:33:57 +04:00
func TestBuildAddSingleFileToRoot ( t * testing . T ) {
2014-09-22 18:23:20 +04:00
name := "testaddimg"
defer deleteImages ( name )
2015-03-04 05:40:16 +03:00
ctx , err := fakeContext ( fmt . Sprintf ( ` FROM busybox
2014-09-22 18:23:20 +04:00
RUN echo ' dockerio : x : 1001 : 1001 : : / bin : / bin / false ' >> / etc / passwd
RUN echo ' dockerio : x : 1001 : ' >> / etc / group
RUN touch / exists
RUN chown dockerio . dockerio / exists
ADD test_file /
RUN [ $ ( ls - l / test_file | awk ' { print $ 3 ":" $ 4 } ' ) = ' root : root ' ]
2015-03-04 05:40:16 +03:00
RUN [ $ ( ls - l / test_file | awk ' { print $ 1 } ' ) = ' % s ' ]
RUN [ $ ( ls - l / exists | awk ' { print $ 3 ":" $ 4 } ' ) = ' dockerio : dockerio ' ] ` , expectedFileChmod ) ,
2014-09-22 18:23:20 +04:00
map [ string ] string {
"test_file" : "test1" ,
} )
2014-05-21 22:29:11 +04:00
if err != nil {
t . Fatal ( err )
}
2014-11-20 20:38:41 +03:00
defer ctx . Close ( )
2014-09-22 18:23:20 +04:00
if _ , err := buildImageFromContext ( name , ctx , true ) ; err != nil {
t . Fatal ( err )
2014-04-09 18:21:22 +04:00
}
logDone ( "build - add single file to root" )
}
2014-05-23 02:12:41 +04:00
// Issue #3960: "ADD src ." hangs
2014-09-19 16:33:57 +04:00
func TestBuildAddSingleFileToWorkdir ( t * testing . T ) {
2014-09-22 18:51:42 +04:00
name := "testaddsinglefiletoworkdir"
defer deleteImages ( name )
ctx , err := fakeContext ( ` FROM busybox
ADD test_file . ` ,
map [ string ] string {
"test_file" : "test1" ,
} )
2014-05-23 02:12:41 +04:00
if err != nil {
t . Fatal ( err )
}
2014-11-20 20:38:41 +03:00
defer ctx . Close ( )
2014-09-22 18:51:42 +04:00
done := make ( chan struct { } )
go func ( ) {
if _ , err := buildImageFromContext ( name , ctx , true ) ; err != nil {
t . Fatal ( err )
}
close ( done )
} ( )
select {
case <- time . After ( 5 * time . Second ) :
t . Fatal ( "Build with adding to workdir timed out" )
case <- done :
2014-05-23 02:12:41 +04:00
}
logDone ( "build - add single file to workdir" )
}
2014-09-19 16:33:57 +04:00
func TestBuildAddSingleFileToExistDir ( t * testing . T ) {
2014-09-22 19:24:14 +04:00
name := "testaddsinglefiletoexistdir"
defer deleteImages ( name )
ctx , err := fakeContext ( ` FROM busybox
RUN echo ' dockerio : x : 1001 : 1001 : : / bin : / bin / false ' >> / etc / passwd
RUN echo ' dockerio : x : 1001 : ' >> / etc / group
RUN mkdir / exists
RUN touch / exists / exists_file
RUN chown - R dockerio . dockerio / exists
ADD test_file / exists /
RUN [ $ ( ls - l / | grep exists | awk ' { print $ 3 ":" $ 4 } ' ) = ' dockerio : dockerio ' ]
RUN [ $ ( ls - l / exists / test_file | awk ' { print $ 3 ":" $ 4 } ' ) = ' root : root ' ]
RUN [ $ ( ls - l / exists / exists_file | awk ' { print $ 3 ":" $ 4 } ' ) = ' dockerio : dockerio ' ] ` ,
map [ string ] string {
"test_file" : "test1" ,
} )
if err != nil {
t . Fatal ( err )
}
2014-11-20 20:38:41 +03:00
defer ctx . Close ( )
2014-09-22 19:24:14 +04:00
if _ , err := buildImageFromContext ( name , ctx , true ) ; err != nil {
t . Fatal ( err )
2014-04-09 18:21:22 +04:00
}
logDone ( "build - add single file to existing dir" )
}
2014-09-19 16:33:57 +04:00
func TestBuildCopyAddMultipleFiles ( t * testing . T ) {
2015-02-26 05:08:17 +03:00
server , err := fakeStorage ( map [ string ] string {
"robots.txt" : "hello" ,
} )
if err != nil {
t . Fatal ( err )
}
defer server . Close ( )
2014-10-02 22:33:12 +04:00
name := "testcopymultiplefilestofile"
defer deleteImages ( name )
2015-02-26 05:08:17 +03:00
ctx , err := fakeContext ( fmt . Sprintf ( ` FROM busybox
2014-10-02 22:33:12 +04:00
RUN echo ' dockerio : x : 1001 : 1001 : : / bin : / bin / false ' >> / etc / passwd
RUN echo ' dockerio : x : 1001 : ' >> / etc / group
RUN mkdir / exists
RUN touch / exists / exists_file
RUN chown - R dockerio . dockerio / exists
COPY test_file1 test_file2 / exists /
2015-02-26 05:08:17 +03:00
ADD test_file3 test_file4 % s / robots . txt / exists /
2014-10-02 22:33:12 +04:00
RUN [ $ ( ls - l / | grep exists | awk ' { print $ 3 ":" $ 4 } ' ) = ' dockerio : dockerio ' ]
RUN [ $ ( ls - l / exists / test_file1 | awk ' { print $ 3 ":" $ 4 } ' ) = ' root : root ' ]
RUN [ $ ( ls - l / exists / test_file2 | awk ' { print $ 3 ":" $ 4 } ' ) = ' root : root ' ]
2014-09-16 20:58:20 +04:00
2014-10-02 22:33:12 +04:00
RUN [ $ ( ls - l / exists / test_file3 | awk ' { print $ 3 ":" $ 4 } ' ) = ' root : root ' ]
RUN [ $ ( ls - l / exists / test_file4 | awk ' { print $ 3 ":" $ 4 } ' ) = ' root : root ' ]
RUN [ $ ( ls - l / exists / robots . txt | awk ' { print $ 3 ":" $ 4 } ' ) = ' root : root ' ]
2014-09-16 20:58:20 +04:00
2014-10-02 22:33:12 +04:00
RUN [ $ ( ls - l / exists / exists_file | awk ' { print $ 3 ":" $ 4 } ' ) = ' dockerio : dockerio ' ]
2015-02-19 13:01:27 +03:00
` , server . URL ( ) ) ,
2014-10-02 22:33:12 +04:00
map [ string ] string {
"test_file1" : "test1" ,
"test_file2" : "test2" ,
"test_file3" : "test3" ,
"test_file4" : "test4" ,
} )
defer ctx . Close ( )
if err != nil {
t . Fatal ( err )
}
if _ , err := buildImageFromContext ( name , ctx , true ) ; err != nil {
t . Fatal ( err )
}
2014-12-27 03:30:34 +03:00
logDone ( "build - multiple file copy/add tests" )
2014-09-16 20:58:20 +04:00
}
2014-09-19 16:33:57 +04:00
func TestBuildAddMultipleFilesToFile ( t * testing . T ) {
2014-09-16 20:58:20 +04:00
name := "testaddmultiplefilestofile"
defer deleteImages ( name )
ctx , err := fakeContext ( ` FROM scratch
ADD file1 . txt file2 . txt test
2014-12-27 03:30:34 +03:00
` ,
2014-09-16 20:58:20 +04:00
map [ string ] string {
"file1.txt" : "test1" ,
"file2.txt" : "test1" ,
} )
defer ctx . Close ( )
if err != nil {
t . Fatal ( err )
}
expected := "When using ADD with more than one source file, the destination must be a directory and end with a /"
if _ , err := buildImageFromContext ( name , ctx , true ) ; err == nil || ! strings . Contains ( err . Error ( ) , expected ) {
2014-12-27 03:30:34 +03:00
t . Fatalf ( "Wrong error: (should contain %q) got:\n%v" , expected , err )
2014-09-16 20:58:20 +04:00
}
logDone ( "build - multiple add files to file" )
}
2014-12-27 03:30:34 +03:00
func TestBuildJSONAddMultipleFilesToFile ( t * testing . T ) {
name := "testjsonaddmultiplefilestofile"
defer deleteImages ( name )
ctx , err := fakeContext ( ` FROM scratch
ADD [ "file1.txt" , "file2.txt" , "test" ]
` ,
map [ string ] string {
"file1.txt" : "test1" ,
"file2.txt" : "test1" ,
} )
defer ctx . Close ( )
if err != nil {
t . Fatal ( err )
}
expected := "When using ADD with more than one source file, the destination must be a directory and end with a /"
if _ , err := buildImageFromContext ( name , ctx , true ) ; err == nil || ! strings . Contains ( err . Error ( ) , expected ) {
t . Fatalf ( "Wrong error: (should contain %q) got:\n%v" , expected , err )
}
logDone ( "build - multiple add files to file json syntax" )
}
2014-09-22 17:41:02 +04:00
func TestBuildAddMultipleFilesToFileWild ( t * testing . T ) {
name := "testaddmultiplefilestofilewild"
defer deleteImages ( name )
ctx , err := fakeContext ( ` FROM scratch
ADD file * . txt test
2014-12-27 03:30:34 +03:00
` ,
2014-09-22 17:41:02 +04:00
map [ string ] string {
"file1.txt" : "test1" ,
"file2.txt" : "test1" ,
} )
defer ctx . Close ( )
if err != nil {
t . Fatal ( err )
}
expected := "When using ADD with more than one source file, the destination must be a directory and end with a /"
if _ , err := buildImageFromContext ( name , ctx , true ) ; err == nil || ! strings . Contains ( err . Error ( ) , expected ) {
2014-12-27 03:30:34 +03:00
t . Fatalf ( "Wrong error: (should contain %q) got:\n%v" , expected , err )
2014-09-22 17:41:02 +04:00
}
logDone ( "build - multiple add files to file wild" )
}
2014-12-27 03:30:34 +03:00
func TestBuildJSONAddMultipleFilesToFileWild ( t * testing . T ) {
name := "testjsonaddmultiplefilestofilewild"
defer deleteImages ( name )
ctx , err := fakeContext ( ` FROM scratch
ADD [ "file*.txt" , "test" ]
` ,
map [ string ] string {
"file1.txt" : "test1" ,
"file2.txt" : "test1" ,
} )
defer ctx . Close ( )
if err != nil {
t . Fatal ( err )
}
expected := "When using ADD with more than one source file, the destination must be a directory and end with a /"
if _ , err := buildImageFromContext ( name , ctx , true ) ; err == nil || ! strings . Contains ( err . Error ( ) , expected ) {
t . Fatalf ( "Wrong error: (should contain %q) got:\n%v" , expected , err )
}
logDone ( "build - multiple add files to file wild json syntax" )
}
2014-09-19 16:33:57 +04:00
func TestBuildCopyMultipleFilesToFile ( t * testing . T ) {
2014-09-16 20:58:20 +04:00
name := "testcopymultiplefilestofile"
defer deleteImages ( name )
ctx , err := fakeContext ( ` FROM scratch
COPY file1 . txt file2 . txt test
2014-12-27 03:30:34 +03:00
` ,
2014-09-16 20:58:20 +04:00
map [ string ] string {
"file1.txt" : "test1" ,
"file2.txt" : "test1" ,
} )
defer ctx . Close ( )
if err != nil {
t . Fatal ( err )
}
expected := "When using COPY with more than one source file, the destination must be a directory and end with a /"
if _ , err := buildImageFromContext ( name , ctx , true ) ; err == nil || ! strings . Contains ( err . Error ( ) , expected ) {
2014-12-27 03:30:34 +03:00
t . Fatalf ( "Wrong error: (should contain %q) got:\n%v" , expected , err )
2014-09-16 20:58:20 +04:00
}
logDone ( "build - multiple copy files to file" )
}
2014-12-27 03:30:34 +03:00
func TestBuildJSONCopyMultipleFilesToFile ( t * testing . T ) {
name := "testjsoncopymultiplefilestofile"
defer deleteImages ( name )
ctx , err := fakeContext ( ` FROM scratch
COPY [ "file1.txt" , "file2.txt" , "test" ]
` ,
map [ string ] string {
"file1.txt" : "test1" ,
"file2.txt" : "test1" ,
} )
defer ctx . Close ( )
if err != nil {
t . Fatal ( err )
}
expected := "When using COPY with more than one source file, the destination must be a directory and end with a /"
if _ , err := buildImageFromContext ( name , ctx , true ) ; err == nil || ! strings . Contains ( err . Error ( ) , expected ) {
t . Fatalf ( "Wrong error: (should contain %q) got:\n%v" , expected , err )
}
logDone ( "build - multiple copy files to file json syntax" )
}
2014-10-06 14:15:09 +04:00
func TestBuildAddFileWithWhitespace ( t * testing . T ) {
name := "testaddfilewithwhitespace"
defer deleteImages ( name )
ctx , err := fakeContext ( ` FROM busybox
RUN mkdir "/test dir"
RUN mkdir "/test_dir"
ADD [ "test file1" , "/test_file1" ]
ADD [ "test_file2" , "/test file2" ]
ADD [ "test file3" , "/test file3" ]
ADD [ "test dir/test_file4" , "/test_dir/test_file4" ]
ADD [ "test_dir/test_file5" , "/test dir/test_file5" ]
ADD [ "test dir/test_file6" , "/test dir/test_file6" ]
RUN [ $ ( cat "/test_file1" ) = ' test1 ' ]
RUN [ $ ( cat "/test file2" ) = ' test2 ' ]
RUN [ $ ( cat "/test file3" ) = ' test3 ' ]
RUN [ $ ( cat "/test_dir/test_file4" ) = ' test4 ' ]
RUN [ $ ( cat "/test dir/test_file5" ) = ' test5 ' ]
RUN [ $ ( cat "/test dir/test_file6" ) = ' test6 ' ] ` ,
map [ string ] string {
"test file1" : "test1" ,
"test_file2" : "test2" ,
"test file3" : "test3" ,
"test dir/test_file4" : "test4" ,
"test_dir/test_file5" : "test5" ,
"test dir/test_file6" : "test6" ,
} )
defer ctx . Close ( )
if err != nil {
t . Fatal ( err )
}
if _ , err := buildImageFromContext ( name , ctx , true ) ; err != nil {
t . Fatal ( err )
}
logDone ( "build - add file with whitespace" )
}
func TestBuildCopyFileWithWhitespace ( t * testing . T ) {
name := "testcopyfilewithwhitespace"
defer deleteImages ( name )
ctx , err := fakeContext ( ` FROM busybox
RUN mkdir "/test dir"
RUN mkdir "/test_dir"
COPY [ "test file1" , "/test_file1" ]
COPY [ "test_file2" , "/test file2" ]
COPY [ "test file3" , "/test file3" ]
COPY [ "test dir/test_file4" , "/test_dir/test_file4" ]
COPY [ "test_dir/test_file5" , "/test dir/test_file5" ]
COPY [ "test dir/test_file6" , "/test dir/test_file6" ]
RUN [ $ ( cat "/test_file1" ) = ' test1 ' ]
RUN [ $ ( cat "/test file2" ) = ' test2 ' ]
RUN [ $ ( cat "/test file3" ) = ' test3 ' ]
RUN [ $ ( cat "/test_dir/test_file4" ) = ' test4 ' ]
RUN [ $ ( cat "/test dir/test_file5" ) = ' test5 ' ]
RUN [ $ ( cat "/test dir/test_file6" ) = ' test6 ' ] ` ,
map [ string ] string {
"test file1" : "test1" ,
"test_file2" : "test2" ,
"test file3" : "test3" ,
"test dir/test_file4" : "test4" ,
"test_dir/test_file5" : "test5" ,
"test dir/test_file6" : "test6" ,
} )
defer ctx . Close ( )
if err != nil {
t . Fatal ( err )
}
if _ , err := buildImageFromContext ( name , ctx , true ) ; err != nil {
t . Fatal ( err )
}
logDone ( "build - copy file with whitespace" )
}
func TestBuildAddMultipleFilesToFileWithWhitespace ( t * testing . T ) {
name := "testaddmultiplefilestofilewithwhitespace"
defer deleteImages ( name )
ctx , err := fakeContext ( ` FROM busybox
ADD [ "test file1" , "test file2" , "test" ]
2014-12-27 03:30:34 +03:00
` ,
2014-10-06 14:15:09 +04:00
map [ string ] string {
"test file1" : "test1" ,
"test file2" : "test2" ,
} )
defer ctx . Close ( )
if err != nil {
t . Fatal ( err )
}
expected := "When using ADD with more than one source file, the destination must be a directory and end with a /"
if _ , err := buildImageFromContext ( name , ctx , true ) ; err == nil || ! strings . Contains ( err . Error ( ) , expected ) {
2014-12-27 03:30:34 +03:00
t . Fatalf ( "Wrong error: (should contain %q) got:\n%v" , expected , err )
2014-10-06 14:15:09 +04:00
}
logDone ( "build - multiple add files to file with whitespace" )
}
func TestBuildCopyMultipleFilesToFileWithWhitespace ( t * testing . T ) {
name := "testcopymultiplefilestofilewithwhitespace"
defer deleteImages ( name )
ctx , err := fakeContext ( ` FROM busybox
COPY [ "test file1" , "test file2" , "test" ]
` ,
map [ string ] string {
"test file1" : "test1" ,
"test file2" : "test2" ,
} )
defer ctx . Close ( )
if err != nil {
t . Fatal ( err )
}
expected := "When using COPY with more than one source file, the destination must be a directory and end with a /"
if _ , err := buildImageFromContext ( name , ctx , true ) ; err == nil || ! strings . Contains ( err . Error ( ) , expected ) {
2014-12-27 03:30:34 +03:00
t . Fatalf ( "Wrong error: (should contain %q) got:\n%v" , expected , err )
2014-10-06 14:15:09 +04:00
}
logDone ( "build - multiple copy files to file with whitespace" )
}
2014-09-22 17:41:02 +04:00
func TestBuildCopyWildcard ( t * testing . T ) {
name := "testcopywildcard"
defer deleteImages ( name )
server , err := fakeStorage ( map [ string ] string {
"robots.txt" : "hello" ,
"index.html" : "world" ,
} )
if err != nil {
t . Fatal ( err )
}
defer server . Close ( )
2015-02-19 13:01:27 +03:00
2014-09-22 17:41:02 +04:00
ctx , err := fakeContext ( fmt . Sprintf ( ` FROM busybox
COPY file * . txt / tmp /
RUN ls / tmp / file1 . txt / tmp / file2 . txt
RUN mkdir / tmp1
COPY dir * / tmp1 /
RUN ls / tmp1 / dirt / tmp1 / nested_file / tmp1 / nested_dir / nest_nest_file
RUN mkdir / tmp2
ADD dir / * dir % s / robots . txt / tmp2 /
RUN ls / tmp2 / nest_nest_file / tmp2 / robots . txt
2015-02-19 13:01:27 +03:00
` , server . URL ( ) ) ,
2014-09-22 17:41:02 +04:00
map [ string ] string {
"file1.txt" : "test1" ,
"file2.txt" : "test2" ,
"dir/nested_file" : "nested file" ,
"dir/nested_dir/nest_nest_file" : "2 times nested" ,
"dirt" : "dirty" ,
} )
defer ctx . Close ( )
if err != nil {
t . Fatal ( err )
}
id1 , err := buildImageFromContext ( name , ctx , true )
if err != nil {
t . Fatal ( err )
}
// Now make sure we use a cache the 2nd time
id2 , err := buildImageFromContext ( name , ctx , true )
if err != nil {
t . Fatal ( err )
}
if id1 != id2 {
2014-10-06 18:26:55 +04:00
t . Fatal ( "didn't use the cache" )
2014-09-22 17:41:02 +04:00
}
logDone ( "build - copy wild card" )
}
func TestBuildCopyWildcardNoFind ( t * testing . T ) {
name := "testcopywildcardnofind"
defer deleteImages ( name )
ctx , err := fakeContext ( ` FROM busybox
COPY file * . txt / tmp /
` , nil )
defer ctx . Close ( )
if err != nil {
t . Fatal ( err )
}
_ , err = buildImageFromContext ( name , ctx , true )
if err == nil {
2014-10-06 18:26:55 +04:00
t . Fatal ( "should have failed to find a file" )
2014-09-22 17:41:02 +04:00
}
if ! strings . Contains ( err . Error ( ) , "No source files were specified" ) {
t . Fatalf ( "Wrong error %v, must be about no source files" , err )
}
logDone ( "build - copy wild card no find" )
}
func TestBuildCopyWildcardCache ( t * testing . T ) {
name := "testcopywildcardcache"
defer deleteImages ( name )
ctx , err := fakeContext ( ` FROM busybox
2014-09-30 00:35:09 +04:00
COPY file1 . txt / tmp / ` ,
2014-09-22 17:41:02 +04:00
map [ string ] string {
"file1.txt" : "test1" ,
} )
defer ctx . Close ( )
if err != nil {
t . Fatal ( err )
}
id1 , err := buildImageFromContext ( name , ctx , true )
if err != nil {
t . Fatal ( err )
}
2014-09-30 00:35:09 +04:00
// Now make sure we use a cache the 2nd time even with wild cards.
// Use the same context so the file is the same and the checksum will match
ctx . Add ( "Dockerfile" , ` FROM busybox
COPY file * . txt / tmp / ` )
2014-09-22 17:41:02 +04:00
2014-09-30 00:35:09 +04:00
id2 , err := buildImageFromContext ( name , ctx , true )
2014-09-22 17:41:02 +04:00
if err != nil {
t . Fatal ( err )
}
if id1 != id2 {
2014-10-06 18:26:55 +04:00
t . Fatal ( "didn't use the cache" )
2014-09-22 17:41:02 +04:00
}
logDone ( "build - copy wild card cache" )
}
2014-10-14 22:47:01 +04:00
func TestBuildAddSingleFileToNonExistingDir ( t * testing . T ) {
name := "testaddsinglefiletononexistingdir"
2014-09-22 19:41:13 +04:00
defer deleteImages ( name )
ctx , err := fakeContext ( ` FROM busybox
RUN echo ' dockerio : x : 1001 : 1001 : : / bin : / bin / false ' >> / etc / passwd
RUN echo ' dockerio : x : 1001 : ' >> / etc / group
RUN touch / exists
RUN chown dockerio . dockerio / exists
ADD test_file / test_dir /
RUN [ $ ( ls - l / | grep test_dir | awk ' { print $ 3 ":" $ 4 } ' ) = ' root : root ' ]
RUN [ $ ( ls - l / test_dir / test_file | awk ' { print $ 3 ":" $ 4 } ' ) = ' root : root ' ]
RUN [ $ ( ls - l / exists | awk ' { print $ 3 ":" $ 4 } ' ) = ' dockerio : dockerio ' ] ` ,
map [ string ] string {
"test_file" : "test1" ,
} )
if err != nil {
t . Fatal ( err )
}
2014-11-20 20:38:41 +03:00
defer ctx . Close ( )
2014-09-22 19:41:13 +04:00
if _ , err := buildImageFromContext ( name , ctx , true ) ; err != nil {
t . Fatal ( err )
2014-04-09 18:21:22 +04:00
}
2014-10-14 22:17:41 +04:00
logDone ( "build - add single file to non-existing dir" )
2014-04-09 18:21:22 +04:00
}
2014-09-19 16:33:57 +04:00
func TestBuildAddDirContentToRoot ( t * testing . T ) {
2014-09-22 20:47:01 +04:00
name := "testadddircontenttoroot"
defer deleteImages ( name )
ctx , err := fakeContext ( ` FROM busybox
RUN echo ' dockerio : x : 1001 : 1001 : : / bin : / bin / false ' >> / etc / passwd
RUN echo ' dockerio : x : 1001 : ' >> / etc / group
RUN touch / exists
RUN chown dockerio . dockerio exists
ADD test_dir /
RUN [ $ ( ls - l / test_file | awk ' { print $ 3 ":" $ 4 } ' ) = ' root : root ' ]
RUN [ $ ( ls - l / exists | awk ' { print $ 3 ":" $ 4 } ' ) = ' dockerio : dockerio ' ] ` ,
map [ string ] string {
"test_dir/test_file" : "test1" ,
} )
if err != nil {
t . Fatal ( err )
}
2014-11-20 20:38:41 +03:00
defer ctx . Close ( )
2014-09-22 20:47:01 +04:00
if _ , err := buildImageFromContext ( name , ctx , true ) ; err != nil {
t . Fatal ( err )
2014-04-09 18:21:22 +04:00
}
logDone ( "build - add directory contents to root" )
}
2014-10-14 22:47:01 +04:00
func TestBuildAddDirContentToExistingDir ( t * testing . T ) {
name := "testadddircontenttoexistingdir"
2014-09-22 21:21:39 +04:00
defer deleteImages ( name )
ctx , err := fakeContext ( ` FROM busybox
RUN echo ' dockerio : x : 1001 : 1001 : : / bin : / bin / false ' >> / etc / passwd
RUN echo ' dockerio : x : 1001 : ' >> / etc / group
RUN mkdir / exists
RUN touch / exists / exists_file
RUN chown - R dockerio . dockerio / exists
ADD test_dir / / exists /
RUN [ $ ( ls - l / | grep exists | awk ' { print $ 3 ":" $ 4 } ' ) = ' dockerio : dockerio ' ]
RUN [ $ ( ls - l / exists / exists_file | awk ' { print $ 3 ":" $ 4 } ' ) = ' dockerio : dockerio ' ]
RUN [ $ ( ls - l / exists / test_file | awk ' { print $ 3 ":" $ 4 } ' ) = ' root : root ' ] ` ,
map [ string ] string {
"test_dir/test_file" : "test1" ,
} )
if err != nil {
t . Fatal ( err )
}
2014-11-20 20:38:41 +03:00
defer ctx . Close ( )
2014-09-22 21:21:39 +04:00
if _ , err := buildImageFromContext ( name , ctx , true ) ; err != nil {
t . Fatal ( err )
2014-04-09 18:21:22 +04:00
}
logDone ( "build - add directory contents to existing dir" )
}
2014-09-19 16:33:57 +04:00
func TestBuildAddWholeDirToRoot ( t * testing . T ) {
2014-09-22 21:36:43 +04:00
name := "testaddwholedirtoroot"
defer deleteImages ( name )
2015-03-04 05:40:16 +03:00
ctx , err := fakeContext ( fmt . Sprintf ( ` FROM busybox
2014-09-22 21:36:43 +04:00
RUN echo ' dockerio : x : 1001 : 1001 : : / bin : / bin / false ' >> / etc / passwd
RUN echo ' dockerio : x : 1001 : ' >> / etc / group
RUN touch / exists
RUN chown dockerio . dockerio exists
ADD test_dir / test_dir
RUN [ $ ( ls - l / | grep test_dir | awk ' { print $ 3 ":" $ 4 } ' ) = ' root : root ' ]
RUN [ $ ( ls - l / | grep test_dir | awk ' { print $ 1 } ' ) = ' drwxr - xr - x ' ]
RUN [ $ ( ls - l / test_dir / test_file | awk ' { print $ 3 ":" $ 4 } ' ) = ' root : root ' ]
2015-03-04 05:40:16 +03:00
RUN [ $ ( ls - l / test_dir / test_file | awk ' { print $ 1 } ' ) = ' % s ' ]
RUN [ $ ( ls - l / exists | awk ' { print $ 3 ":" $ 4 } ' ) = ' dockerio : dockerio ' ] ` , expectedFileChmod ) ,
2014-09-22 21:36:43 +04:00
map [ string ] string {
"test_dir/test_file" : "test1" ,
} )
2014-09-17 20:34:45 +04:00
if err != nil {
2014-05-21 22:29:11 +04:00
t . Fatal ( err )
}
2014-11-20 20:38:41 +03:00
defer ctx . Close ( )
2014-09-22 21:36:43 +04:00
if _ , err := buildImageFromContext ( name , ctx , true ) ; err != nil {
2014-05-21 22:29:11 +04:00
t . Fatal ( err )
}
2014-04-09 18:21:22 +04:00
logDone ( "build - add whole directory to root" )
}
2014-09-22 21:26:51 +04:00
// Testing #5941
2014-09-19 16:33:57 +04:00
func TestBuildAddEtcToRoot ( t * testing . T ) {
2014-09-22 21:26:51 +04:00
name := "testaddetctoroot"
defer deleteImages ( name )
ctx , err := fakeContext ( ` FROM scratch
ADD . / ` ,
map [ string ] string {
"etc/test_file" : "test1" ,
} )
if err != nil {
t . Fatal ( err )
}
2014-11-20 20:38:41 +03:00
defer ctx . Close ( )
2014-09-22 21:26:51 +04:00
if _ , err := buildImageFromContext ( name , ctx , true ) ; err != nil {
t . Fatal ( err )
2014-05-21 00:39:46 +04:00
}
logDone ( "build - add etc directory to root" )
}
2014-12-03 05:45:07 +03:00
// Testing #9401
func TestBuildAddPreservesFilesSpecialBits ( t * testing . T ) {
name := "testaddpreservesfilesspecialbits"
defer deleteImages ( name )
ctx , err := fakeContext ( ` FROM busybox
ADD suidbin / usr / bin / suidbin
RUN chmod 4755 / usr / bin / suidbin
RUN [ $ ( ls - l / usr / bin / suidbin | awk ' { print $ 1 } ' ) = ' - rwsr - xr - x ' ]
ADD . / data / /
RUN [ $ ( ls - l / usr / bin / suidbin | awk ' { print $ 1 } ' ) = ' - rwsr - xr - x ' ] ` ,
map [ string ] string {
"suidbin" : "suidbin" ,
"/data/usr/test_file" : "test1" ,
} )
if err != nil {
t . Fatal ( err )
}
defer ctx . Close ( )
if _ , err := buildImageFromContext ( name , ctx , true ) ; err != nil {
t . Fatal ( err )
}
logDone ( "build - add preserves files special bits" )
}
2014-09-18 09:09:10 +04:00
func TestBuildCopySingleFileToRoot ( t * testing . T ) {
2014-10-14 21:07:04 +04:00
name := "testcopysinglefiletoroot"
defer deleteImages ( name )
2015-03-04 05:40:16 +03:00
ctx , err := fakeContext ( fmt . Sprintf ( ` FROM busybox
2014-10-14 21:07:04 +04:00
RUN echo ' dockerio : x : 1001 : 1001 : : / bin : / bin / false ' >> / etc / passwd
RUN echo ' dockerio : x : 1001 : ' >> / etc / group
RUN touch / exists
RUN chown dockerio . dockerio / exists
COPY test_file /
RUN [ $ ( ls - l / test_file | awk ' { print $ 3 ":" $ 4 } ' ) = ' root : root ' ]
2015-03-04 05:40:16 +03:00
RUN [ $ ( ls - l / test_file | awk ' { print $ 1 } ' ) = ' % s ' ]
RUN [ $ ( ls - l / exists | awk ' { print $ 3 ":" $ 4 } ' ) = ' dockerio : dockerio ' ] ` , expectedFileChmod ) ,
2014-10-14 21:07:04 +04:00
map [ string ] string {
"test_file" : "test1" ,
} )
2014-05-28 21:53:16 +04:00
if err != nil {
t . Fatal ( err )
}
2014-11-20 20:38:41 +03:00
defer ctx . Close ( )
2014-10-14 21:07:04 +04:00
if _ , err := buildImageFromContext ( name , ctx , true ) ; err != nil {
t . Fatal ( err )
2014-05-28 21:53:16 +04:00
}
logDone ( "build - copy single file to root" )
}
// Issue #3960: "ADD src ." hangs - adapted for COPY
2014-09-18 09:09:10 +04:00
func TestBuildCopySingleFileToWorkdir ( t * testing . T ) {
2014-10-14 21:12:11 +04:00
name := "testcopysinglefiletoworkdir"
defer deleteImages ( name )
ctx , err := fakeContext ( ` FROM busybox
COPY test_file . ` ,
map [ string ] string {
"test_file" : "test1" ,
} )
2014-05-28 21:53:16 +04:00
if err != nil {
t . Fatal ( err )
}
2014-11-20 20:38:41 +03:00
defer ctx . Close ( )
2014-10-14 21:12:11 +04:00
done := make ( chan struct { } )
go func ( ) {
if _ , err := buildImageFromContext ( name , ctx , true ) ; err != nil {
t . Fatal ( err )
}
close ( done )
} ( )
select {
case <- time . After ( 5 * time . Second ) :
t . Fatal ( "Build with adding to workdir timed out" )
case <- done :
2014-05-28 21:53:16 +04:00
}
logDone ( "build - copy single file to workdir" )
}
2014-09-18 09:09:10 +04:00
func TestBuildCopySingleFileToExistDir ( t * testing . T ) {
2014-10-14 21:15:45 +04:00
name := "testcopysinglefiletoexistdir"
defer deleteImages ( name )
ctx , err := fakeContext ( ` FROM busybox
RUN echo ' dockerio : x : 1001 : 1001 : : / bin : / bin / false ' >> / etc / passwd
RUN echo ' dockerio : x : 1001 : ' >> / etc / group
RUN mkdir / exists
RUN touch / exists / exists_file
RUN chown - R dockerio . dockerio / exists
COPY test_file / exists /
RUN [ $ ( ls - l / | grep exists | awk ' { print $ 3 ":" $ 4 } ' ) = ' dockerio : dockerio ' ]
RUN [ $ ( ls - l / exists / test_file | awk ' { print $ 3 ":" $ 4 } ' ) = ' root : root ' ]
RUN [ $ ( ls - l / exists / exists_file | awk ' { print $ 3 ":" $ 4 } ' ) = ' dockerio : dockerio ' ] ` ,
map [ string ] string {
"test_file" : "test1" ,
} )
if err != nil {
t . Fatal ( err )
}
2014-11-20 20:38:41 +03:00
defer ctx . Close ( )
2014-10-14 21:15:45 +04:00
if _ , err := buildImageFromContext ( name , ctx , true ) ; err != nil {
t . Fatal ( err )
2014-05-28 21:53:16 +04:00
}
2014-09-18 09:02:05 +04:00
logDone ( "build - copy single file to existing dir" )
2014-05-28 21:53:16 +04:00
}
2014-09-18 09:09:10 +04:00
func TestBuildCopySingleFileToNonExistDir ( t * testing . T ) {
2014-10-14 21:19:45 +04:00
name := "testcopysinglefiletononexistdir"
defer deleteImages ( name )
ctx , err := fakeContext ( ` FROM busybox
RUN echo ' dockerio : x : 1001 : 1001 : : / bin : / bin / false ' >> / etc / passwd
RUN echo ' dockerio : x : 1001 : ' >> / etc / group
RUN touch / exists
RUN chown dockerio . dockerio / exists
COPY test_file / test_dir /
RUN [ $ ( ls - l / | grep test_dir | awk ' { print $ 3 ":" $ 4 } ' ) = ' root : root ' ]
RUN [ $ ( ls - l / test_dir / test_file | awk ' { print $ 3 ":" $ 4 } ' ) = ' root : root ' ]
RUN [ $ ( ls - l / exists | awk ' { print $ 3 ":" $ 4 } ' ) = ' dockerio : dockerio ' ] ` ,
map [ string ] string {
"test_file" : "test1" ,
} )
if err != nil {
t . Fatal ( err )
}
2014-11-20 20:38:41 +03:00
defer ctx . Close ( )
2014-10-14 21:19:45 +04:00
if _ , err := buildImageFromContext ( name , ctx , true ) ; err != nil {
t . Fatal ( err )
2014-05-28 21:53:16 +04:00
}
logDone ( "build - copy single file to non-existing dir" )
}
2014-09-18 09:09:10 +04:00
func TestBuildCopyDirContentToRoot ( t * testing . T ) {
2014-10-14 21:22:06 +04:00
name := "testcopydircontenttoroot"
defer deleteImages ( name )
ctx , err := fakeContext ( ` FROM busybox
RUN echo ' dockerio : x : 1001 : 1001 : : / bin : / bin / false ' >> / etc / passwd
RUN echo ' dockerio : x : 1001 : ' >> / etc / group
RUN touch / exists
RUN chown dockerio . dockerio exists
COPY test_dir /
RUN [ $ ( ls - l / test_file | awk ' { print $ 3 ":" $ 4 } ' ) = ' root : root ' ]
RUN [ $ ( ls - l / exists | awk ' { print $ 3 ":" $ 4 } ' ) = ' dockerio : dockerio ' ] ` ,
map [ string ] string {
"test_dir/test_file" : "test1" ,
} )
if err != nil {
t . Fatal ( err )
}
2014-11-20 20:38:41 +03:00
defer ctx . Close ( )
2014-10-14 21:22:06 +04:00
if _ , err := buildImageFromContext ( name , ctx , true ) ; err != nil {
t . Fatal ( err )
2014-05-28 21:53:16 +04:00
}
logDone ( "build - copy directory contents to root" )
}
2014-09-18 09:09:10 +04:00
func TestBuildCopyDirContentToExistDir ( t * testing . T ) {
2014-10-14 21:26:20 +04:00
name := "testcopydircontenttoexistdir"
defer deleteImages ( name )
ctx , err := fakeContext ( ` FROM busybox
RUN echo ' dockerio : x : 1001 : 1001 : : / bin : / bin / false ' >> / etc / passwd
RUN echo ' dockerio : x : 1001 : ' >> / etc / group
RUN mkdir / exists
RUN touch / exists / exists_file
RUN chown - R dockerio . dockerio / exists
COPY test_dir / / exists /
RUN [ $ ( ls - l / | grep exists | awk ' { print $ 3 ":" $ 4 } ' ) = ' dockerio : dockerio ' ]
RUN [ $ ( ls - l / exists / exists_file | awk ' { print $ 3 ":" $ 4 } ' ) = ' dockerio : dockerio ' ]
RUN [ $ ( ls - l / exists / test_file | awk ' { print $ 3 ":" $ 4 } ' ) = ' root : root ' ] ` ,
map [ string ] string {
"test_dir/test_file" : "test1" ,
} )
if err != nil {
t . Fatal ( err )
}
2014-11-20 20:38:41 +03:00
defer ctx . Close ( )
2014-10-14 21:26:20 +04:00
if _ , err := buildImageFromContext ( name , ctx , true ) ; err != nil {
t . Fatal ( err )
2014-05-28 21:53:16 +04:00
}
logDone ( "build - copy directory contents to existing dir" )
}
2014-09-18 09:09:10 +04:00
func TestBuildCopyWholeDirToRoot ( t * testing . T ) {
2014-10-14 21:29:22 +04:00
name := "testcopywholedirtoroot"
defer deleteImages ( name )
2015-03-04 05:40:16 +03:00
ctx , err := fakeContext ( fmt . Sprintf ( ` FROM busybox
2014-10-14 21:29:22 +04:00
RUN echo ' dockerio : x : 1001 : 1001 : : / bin : / bin / false ' >> / etc / passwd
RUN echo ' dockerio : x : 1001 : ' >> / etc / group
RUN touch / exists
RUN chown dockerio . dockerio exists
COPY test_dir / test_dir
RUN [ $ ( ls - l / | grep test_dir | awk ' { print $ 3 ":" $ 4 } ' ) = ' root : root ' ]
RUN [ $ ( ls - l / | grep test_dir | awk ' { print $ 1 } ' ) = ' drwxr - xr - x ' ]
RUN [ $ ( ls - l / test_dir / test_file | awk ' { print $ 3 ":" $ 4 } ' ) = ' root : root ' ]
2015-03-04 05:40:16 +03:00
RUN [ $ ( ls - l / test_dir / test_file | awk ' { print $ 1 } ' ) = ' % s ' ]
RUN [ $ ( ls - l / exists | awk ' { print $ 3 ":" $ 4 } ' ) = ' dockerio : dockerio ' ] ` , expectedFileChmod ) ,
2014-10-14 21:29:22 +04:00
map [ string ] string {
"test_dir/test_file" : "test1" ,
} )
2014-09-17 20:34:45 +04:00
if err != nil {
2014-05-28 21:53:16 +04:00
t . Fatal ( err )
}
2014-11-20 20:38:41 +03:00
defer ctx . Close ( )
2014-10-14 21:29:22 +04:00
if _ , err := buildImageFromContext ( name , ctx , true ) ; err != nil {
2014-05-28 21:53:16 +04:00
t . Fatal ( err )
}
logDone ( "build - copy whole directory to root" )
}
2014-09-18 09:09:10 +04:00
func TestBuildCopyEtcToRoot ( t * testing . T ) {
2014-10-14 21:32:00 +04:00
name := "testcopyetctoroot"
defer deleteImages ( name )
ctx , err := fakeContext ( ` FROM scratch
COPY . / ` ,
map [ string ] string {
"etc/test_file" : "test1" ,
} )
if err != nil {
t . Fatal ( err )
}
2014-11-20 20:38:41 +03:00
defer ctx . Close ( )
2014-10-14 21:32:00 +04:00
if _ , err := buildImageFromContext ( name , ctx , true ) ; err != nil {
t . Fatal ( err )
2014-05-28 21:53:16 +04:00
}
logDone ( "build - copy etc directory to root" )
}
2014-09-18 09:09:10 +04:00
func TestBuildCopyDisallowRemote ( t * testing . T ) {
2014-10-14 21:37:05 +04:00
name := "testcopydisallowremote"
defer deleteImages ( name )
_ , out , err := buildImageWithOut ( name , ` FROM scratch
COPY https : //index.docker.io/robots.txt /`,
true )
if err == nil || ! strings . Contains ( out , "Source can't be a URL for COPY" ) {
2014-11-05 19:26:22 +03:00
t . Fatalf ( "Error should be about disallowed remote source, got err: %s, out: %q" , err , out )
2014-05-28 21:53:16 +04:00
}
logDone ( "build - copy - disallow copy from remote" )
}
2014-11-27 23:14:15 +03:00
func TestBuildAddBadLinks ( t * testing . T ) {
const (
dockerfile = `
FROM scratch
ADD links . tar /
ADD foo . txt / symlink /
`
targetFile = "foo.txt"
)
var (
name = "test-link-absolute"
)
defer deleteImages ( name )
ctx , err := fakeContext ( dockerfile , nil )
if err != nil {
t . Fatal ( err )
}
defer ctx . Close ( )
tempDir , err := ioutil . TempDir ( "" , "test-link-absolute-temp-" )
if err != nil {
t . Fatalf ( "failed to create temporary directory: %s" , tempDir )
}
defer os . RemoveAll ( tempDir )
2015-02-18 10:20:20 +03:00
var symlinkTarget string
if runtime . GOOS == "windows" {
var driveLetter string
if abs , err := filepath . Abs ( tempDir ) ; err != nil {
t . Fatal ( err )
} else {
driveLetter = abs [ : 1 ]
}
tempDirWithoutDrive := tempDir [ 2 : ]
symlinkTarget = fmt . Sprintf ( ` %s:\..\..\..\..\..\..\..\..\..\..\..\..%s ` , driveLetter , tempDirWithoutDrive )
} else {
symlinkTarget = fmt . Sprintf ( "/../../../../../../../../../../../..%s" , tempDir )
}
2014-11-27 23:14:15 +03:00
tarPath := filepath . Join ( ctx . Dir , "links.tar" )
nonExistingFile := filepath . Join ( tempDir , targetFile )
fooPath := filepath . Join ( ctx . Dir , targetFile )
tarOut , err := os . Create ( tarPath )
if err != nil {
t . Fatal ( err )
}
tarWriter := tar . NewWriter ( tarOut )
header := & tar . Header {
Name : "symlink" ,
Typeflag : tar . TypeSymlink ,
Linkname : symlinkTarget ,
Mode : 0755 ,
Uid : 0 ,
Gid : 0 ,
}
err = tarWriter . WriteHeader ( header )
if err != nil {
t . Fatal ( err )
}
tarWriter . Close ( )
tarOut . Close ( )
foo , err := os . Create ( fooPath )
if err != nil {
t . Fatal ( err )
}
defer foo . Close ( )
if _ , err := foo . WriteString ( "test" ) ; err != nil {
t . Fatal ( err )
}
if _ , err := buildImageFromContext ( name , ctx , true ) ; err != nil {
t . Fatal ( err )
}
if _ , err := os . Stat ( nonExistingFile ) ; err == nil || err != nil && ! os . IsNotExist ( err ) {
t . Fatalf ( "%s shouldn't have been written and it shouldn't exist" , nonExistingFile )
}
logDone ( "build - ADD must add files in container" )
}
2014-11-27 23:39:43 +03:00
func TestBuildAddBadLinksVolume ( t * testing . T ) {
const (
dockerfileTemplate = `
FROM busybox
RUN ln - s / . . / . . / . . / . . / . . / . . / . . / . . / % s / x
VOLUME / x
ADD foo . txt / x / `
targetFile = "foo.txt"
)
var (
name = "test-link-absolute-volume"
dockerfile = ""
)
defer deleteImages ( name )
tempDir , err := ioutil . TempDir ( "" , "test-link-absolute-volume-temp-" )
if err != nil {
t . Fatalf ( "failed to create temporary directory: %s" , tempDir )
}
defer os . RemoveAll ( tempDir )
dockerfile = fmt . Sprintf ( dockerfileTemplate , tempDir )
nonExistingFile := filepath . Join ( tempDir , targetFile )
ctx , err := fakeContext ( dockerfile , nil )
if err != nil {
t . Fatal ( err )
}
defer ctx . Close ( )
fooPath := filepath . Join ( ctx . Dir , targetFile )
foo , err := os . Create ( fooPath )
if err != nil {
t . Fatal ( err )
}
defer foo . Close ( )
if _ , err := foo . WriteString ( "test" ) ; err != nil {
t . Fatal ( err )
}
if _ , err := buildImageFromContext ( name , ctx , true ) ; err != nil {
t . Fatal ( err )
}
if _ , err := os . Stat ( nonExistingFile ) ; err == nil || err != nil && ! os . IsNotExist ( err ) {
t . Fatalf ( "%s shouldn't have been written and it shouldn't exist" , nonExistingFile )
}
logDone ( "build - ADD should add files in volume" )
}
2014-05-13 22:49:12 +04:00
// Issue #5270 - ensure we throw a better error than "unexpected EOF"
// when we can't access files in the context.
func TestBuildWithInaccessibleFilesInContext ( t * testing . T ) {
2015-02-20 12:37:27 +03:00
testRequires ( t , UnixCli ) // test uses chown/chmod: not available on windows
2014-05-13 22:49:12 +04:00
{
2014-09-24 16:42:17 +04:00
name := "testbuildinaccessiblefiles"
defer deleteImages ( name )
ctx , err := fakeContext ( "FROM scratch\nADD . /foo/" , map [ string ] string { "fileWithoutReadAccess" : "foo" } )
if err != nil {
t . Fatal ( err )
}
defer ctx . Close ( )
2014-05-13 22:49:12 +04:00
// This is used to ensure we detect inaccessible files early during build in the cli client
2014-09-24 16:42:17 +04:00
pathToFileWithoutReadAccess := filepath . Join ( ctx . Dir , "fileWithoutReadAccess" )
2014-05-13 22:49:12 +04:00
2014-10-15 00:51:12 +04:00
if err = os . Chown ( pathToFileWithoutReadAccess , 0 , 0 ) ; err != nil {
t . Fatalf ( "failed to chown file to root: %s" , err )
}
if err = os . Chmod ( pathToFileWithoutReadAccess , 0700 ) ; err != nil {
t . Fatalf ( "failed to chmod file to 700: %s" , err )
}
2014-09-24 16:42:17 +04:00
buildCmd := exec . Command ( "su" , "unprivilegeduser" , "-c" , fmt . Sprintf ( "%s build -t %s ." , dockerBinary , name ) )
buildCmd . Dir = ctx . Dir
2014-10-15 00:51:12 +04:00
out , _ , err := runCommandWithOutput ( buildCmd )
if err == nil {
2014-05-13 22:49:12 +04:00
t . Fatalf ( "build should have failed: %s %s" , err , out )
}
// check if we've detected the failure before we started building
if ! strings . Contains ( out , "no permission to read from " ) {
2014-05-21 22:29:11 +04:00
t . Fatalf ( "output should've contained the string: no permission to read from but contained: %s" , out )
2014-05-13 22:49:12 +04:00
}
if ! strings . Contains ( out , "Error checking context is accessible" ) {
t . Fatalf ( "output should've contained the string: Error checking context is accessible" )
}
}
{
2014-09-24 16:42:17 +04:00
name := "testbuildinaccessibledirectory"
defer deleteImages ( name )
ctx , err := fakeContext ( "FROM scratch\nADD . /foo/" , map [ string ] string { "directoryWeCantStat/bar" : "foo" } )
if err != nil {
t . Fatal ( err )
}
defer ctx . Close ( )
2014-05-13 22:49:12 +04:00
// This is used to ensure we detect inaccessible directories early during build in the cli client
2014-09-24 16:42:17 +04:00
pathToDirectoryWithoutReadAccess := filepath . Join ( ctx . Dir , "directoryWeCantStat" )
2014-05-13 22:49:12 +04:00
pathToFileInDirectoryWithoutReadAccess := filepath . Join ( pathToDirectoryWithoutReadAccess , "bar" )
2014-10-15 00:51:12 +04:00
if err = os . Chown ( pathToDirectoryWithoutReadAccess , 0 , 0 ) ; err != nil {
t . Fatalf ( "failed to chown directory to root: %s" , err )
}
if err = os . Chmod ( pathToDirectoryWithoutReadAccess , 0444 ) ; err != nil {
2015-02-03 19:13:33 +03:00
t . Fatalf ( "failed to chmod directory to 444: %s" , err )
2014-10-15 00:51:12 +04:00
}
if err = os . Chmod ( pathToFileInDirectoryWithoutReadAccess , 0700 ) ; err != nil {
2015-02-03 19:13:33 +03:00
t . Fatalf ( "failed to chmod file to 700: %s" , err )
2014-10-15 00:51:12 +04:00
}
2014-05-13 22:49:12 +04:00
2014-09-24 16:42:17 +04:00
buildCmd := exec . Command ( "su" , "unprivilegeduser" , "-c" , fmt . Sprintf ( "%s build -t %s ." , dockerBinary , name ) )
buildCmd . Dir = ctx . Dir
2014-10-15 00:51:12 +04:00
out , _ , err := runCommandWithOutput ( buildCmd )
if err == nil {
2014-05-13 22:49:12 +04:00
t . Fatalf ( "build should have failed: %s %s" , err , out )
}
// check if we've detected the failure before we started building
if ! strings . Contains ( out , "can't stat" ) {
t . Fatalf ( "output should've contained the string: can't access %s" , out )
}
if ! strings . Contains ( out , "Error checking context is accessible" ) {
t . Fatalf ( "output should've contained the string: Error checking context is accessible" )
}
}
{
2014-09-24 16:42:17 +04:00
name := "testlinksok"
defer deleteImages ( name )
ctx , err := fakeContext ( "FROM scratch\nADD . /foo/" , nil )
if err != nil {
t . Fatal ( err )
}
defer ctx . Close ( )
2014-11-17 19:05:49 +03:00
target := "../../../../../../../../../../../../../../../../../../../azA"
if err := os . Symlink ( filepath . Join ( ctx . Dir , "g" ) , target ) ; err != nil {
2014-09-24 16:42:17 +04:00
t . Fatal ( err )
}
2014-11-17 19:05:49 +03:00
defer os . Remove ( target )
2014-05-13 22:49:12 +04:00
// This is used to ensure we don't follow links when checking if everything in the context is accessible
// This test doesn't require that we run commands as an unprivileged user
2014-09-24 16:42:17 +04:00
if _ , err := buildImageFromContext ( name , ctx , true ) ; err != nil {
t . Fatal ( err )
2014-05-13 22:49:12 +04:00
}
2014-07-07 16:23:07 +04:00
}
{
2014-09-24 16:42:17 +04:00
name := "testbuildignoredinaccessible"
defer deleteImages ( name )
ctx , err := fakeContext ( "FROM scratch\nADD . /foo/" ,
map [ string ] string {
"directoryWeCantStat/bar" : "foo" ,
".dockerignore" : "directoryWeCantStat" ,
} )
if err != nil {
t . Fatal ( err )
}
defer ctx . Close ( )
2014-07-07 16:23:07 +04:00
// This is used to ensure we don't try to add inaccessible files when they are ignored by a .dockerignore pattern
2014-09-24 16:42:17 +04:00
pathToDirectoryWithoutReadAccess := filepath . Join ( ctx . Dir , "directoryWeCantStat" )
2014-07-07 16:23:07 +04:00
pathToFileInDirectoryWithoutReadAccess := filepath . Join ( pathToDirectoryWithoutReadAccess , "bar" )
2014-10-15 00:51:12 +04:00
if err = os . Chown ( pathToDirectoryWithoutReadAccess , 0 , 0 ) ; err != nil {
t . Fatalf ( "failed to chown directory to root: %s" , err )
}
if err = os . Chmod ( pathToDirectoryWithoutReadAccess , 0444 ) ; err != nil {
t . Fatalf ( "failed to chmod directory to 755: %s" , err )
}
if err = os . Chmod ( pathToFileInDirectoryWithoutReadAccess , 0700 ) ; err != nil {
t . Fatalf ( "failed to chmod file to 444: %s" , err )
}
2014-07-07 16:23:07 +04:00
2014-09-24 16:42:17 +04:00
buildCmd := exec . Command ( "su" , "unprivilegeduser" , "-c" , fmt . Sprintf ( "%s build -t %s ." , dockerBinary , name ) )
buildCmd . Dir = ctx . Dir
2014-10-15 00:51:12 +04:00
if out , _ , err := runCommandWithOutput ( buildCmd ) ; err != nil {
2014-07-07 16:23:07 +04:00
t . Fatalf ( "build should have worked: %s %s" , err , out )
}
2014-05-13 22:49:12 +04:00
}
2015-02-10 02:01:52 +03:00
logDone ( "build - ADD from context with inaccessible files must not pass" )
2014-05-13 22:49:12 +04:00
logDone ( "build - ADD from context with accessible links must work" )
2014-07-07 16:23:07 +04:00
logDone ( "build - ADD from context with ignored inaccessible files must work" )
2014-05-13 22:49:12 +04:00
}
2014-05-19 20:46:25 +04:00
func TestBuildForceRm ( t * testing . T ) {
containerCountBefore , err := getContainerCount ( )
if err != nil {
t . Fatalf ( "failed to get the container count: %s" , err )
}
2014-09-24 12:29:27 +04:00
name := "testbuildforcerm"
defer deleteImages ( name )
ctx , err := fakeContext ( "FROM scratch\nRUN true\nRUN thiswillfail" , nil )
if err != nil {
t . Fatal ( err )
}
defer ctx . Close ( )
2014-05-19 20:46:25 +04:00
2014-09-24 12:29:27 +04:00
buildCmd := exec . Command ( dockerBinary , "build" , "-t" , name , "--force-rm" , "." )
buildCmd . Dir = ctx . Dir
2014-10-15 00:51:12 +04:00
if out , _ , err := runCommandWithOutput ( buildCmd ) ; err == nil {
2014-11-05 19:26:22 +03:00
t . Fatalf ( "failed to build the image: %s, %v" , out , err )
2014-05-19 20:46:25 +04:00
}
containerCountAfter , err := getContainerCount ( )
if err != nil {
t . Fatalf ( "failed to get the container count: %s" , err )
}
if containerCountBefore != containerCountAfter {
t . Fatalf ( "--force-rm shouldn't have left containers behind" )
}
logDone ( "build - ensure --force-rm doesn't leave containers behind" )
}
2014-05-19 22:21:25 +04:00
func TestBuildRm ( t * testing . T ) {
2014-09-24 13:15:55 +04:00
name := "testbuildrm"
defer deleteImages ( name )
ctx , err := fakeContext ( "FROM scratch\nADD foo /\nADD foo /" , map [ string ] string { "foo" : "bar" } )
if err != nil {
t . Fatal ( err )
}
defer ctx . Close ( )
2014-05-19 22:21:25 +04:00
{
containerCountBefore , err := getContainerCount ( )
if err != nil {
t . Fatalf ( "failed to get the container count: %s" , err )
}
2014-10-15 00:51:12 +04:00
out , _ , err := dockerCmdInDir ( t , ctx . Dir , "build" , "--rm" , "-t" , name , "." )
2014-05-19 22:21:25 +04:00
2014-10-15 00:51:12 +04:00
if err != nil {
2014-09-24 13:15:55 +04:00
t . Fatal ( "failed to build the image" , out )
2014-05-19 22:21:25 +04:00
}
containerCountAfter , err := getContainerCount ( )
if err != nil {
t . Fatalf ( "failed to get the container count: %s" , err )
}
if containerCountBefore != containerCountAfter {
t . Fatalf ( "-rm shouldn't have left containers behind" )
}
2014-09-24 13:15:55 +04:00
deleteImages ( name )
2014-05-19 22:21:25 +04:00
}
{
containerCountBefore , err := getContainerCount ( )
if err != nil {
t . Fatalf ( "failed to get the container count: %s" , err )
}
2014-10-15 00:51:12 +04:00
out , _ , err := dockerCmdInDir ( t , ctx . Dir , "build" , "-t" , name , "." )
2014-05-19 22:21:25 +04:00
2014-10-15 00:51:12 +04:00
if err != nil {
2014-09-24 13:15:55 +04:00
t . Fatal ( "failed to build the image" , out )
2014-05-19 22:21:25 +04:00
}
containerCountAfter , err := getContainerCount ( )
if err != nil {
t . Fatalf ( "failed to get the container count: %s" , err )
}
if containerCountBefore != containerCountAfter {
t . Fatalf ( "--rm shouldn't have left containers behind" )
}
2014-09-24 13:15:55 +04:00
deleteImages ( name )
2014-05-19 22:21:25 +04:00
}
{
containerCountBefore , err := getContainerCount ( )
if err != nil {
t . Fatalf ( "failed to get the container count: %s" , err )
}
2014-10-15 00:51:12 +04:00
out , _ , err := dockerCmdInDir ( t , ctx . Dir , "build" , "--rm=false" , "-t" , name , "." )
2014-05-19 22:21:25 +04:00
2014-10-15 00:51:12 +04:00
if err != nil {
2014-09-24 13:15:55 +04:00
t . Fatal ( "failed to build the image" , out )
2014-05-19 22:21:25 +04:00
}
containerCountAfter , err := getContainerCount ( )
if err != nil {
t . Fatalf ( "failed to get the container count: %s" , err )
}
if containerCountBefore == containerCountAfter {
t . Fatalf ( "--rm=false should have left containers behind" )
}
deleteAllContainers ( )
2014-09-24 13:15:55 +04:00
deleteImages ( name )
2014-05-19 22:21:25 +04:00
}
logDone ( "build - ensure --rm doesn't leave containers behind and that --rm=true is the default" )
logDone ( "build - ensure --rm=false overrides the default" )
}
2014-06-17 10:04:25 +04:00
2014-05-31 16:43:32 +04:00
func TestBuildWithVolumes ( t * testing . T ) {
2014-07-09 00:27:58 +04:00
var (
result map [ string ] map [ string ] struct { }
name = "testbuildvolumes"
emptyMap = make ( map [ string ] struct { } )
2014-09-11 17:27:51 +04:00
expected = map [ string ] map [ string ] struct { } {
"/test1" : emptyMap ,
"/test2" : emptyMap ,
"/test3" : emptyMap ,
"/test4" : emptyMap ,
"/test5" : emptyMap ,
"/test6" : emptyMap ,
"[/test7" : emptyMap ,
"/test8]" : emptyMap ,
}
2014-07-09 00:27:58 +04:00
)
2014-05-31 16:43:32 +04:00
defer deleteImages ( name )
_ , err := buildImage ( name ,
` FROM scratch
VOLUME / test1
2014-09-11 17:27:51 +04:00
VOLUME / test2
VOLUME / test3 / test4
VOLUME [ "/test5" , "/test6" ]
VOLUME [ / test7 / test8 ]
` ,
2014-05-31 16:43:32 +04:00
true )
if err != nil {
t . Fatal ( err )
}
2014-07-09 00:27:58 +04:00
res , err := inspectFieldJSON ( name , "Config.Volumes" )
2014-05-31 16:43:32 +04:00
if err != nil {
t . Fatal ( err )
}
2014-07-09 00:27:58 +04:00
err = unmarshalJSON ( [ ] byte ( res ) , & result )
if err != nil {
t . Fatal ( err )
2014-05-31 16:43:32 +04:00
}
2014-07-09 00:27:58 +04:00
2014-12-04 04:52:06 +03:00
equal := reflect . DeepEqual ( & result , & expected )
2014-07-09 00:27:58 +04:00
if ! equal {
t . Fatalf ( "Volumes %s, expected %s" , result , expected )
}
2014-05-31 16:43:32 +04:00
logDone ( "build - with volumes" )
2014-05-22 23:16:27 +04:00
}
2014-05-25 22:26:50 +04:00
func TestBuildMaintainer ( t * testing . T ) {
2014-05-31 16:43:32 +04:00
name := "testbuildmaintainer"
expected := "dockerio"
defer deleteImages ( name )
_ , err := buildImage ( name ,
` FROM scratch
MAINTAINER dockerio ` ,
true )
if err != nil {
t . Fatal ( err )
}
res , err := inspectField ( name , "Author" )
if err != nil {
t . Fatal ( err )
}
if res != expected {
t . Fatalf ( "Maintainer %s, expected %s" , res , expected )
}
2014-05-25 22:26:50 +04:00
logDone ( "build - maintainer" )
}
2014-05-25 22:28:14 +04:00
func TestBuildUser ( t * testing . T ) {
2014-05-31 16:43:32 +04:00
name := "testbuilduser"
expected := "dockerio"
defer deleteImages ( name )
_ , err := buildImage ( name ,
` FROM busybox
2014-05-25 22:28:14 +04:00
RUN echo ' dockerio : x : 1001 : 1001 : : / bin : / bin / false ' >> / etc / passwd
USER dockerio
2014-05-31 16:43:32 +04:00
RUN [ $ ( whoami ) = ' dockerio ' ] ` ,
true )
if err != nil {
t . Fatal ( err )
}
res , err := inspectField ( name , "Config.User" )
if err != nil {
t . Fatal ( err )
}
if res != expected {
t . Fatalf ( "User %s, expected %s" , res , expected )
}
2014-05-25 22:28:14 +04:00
logDone ( "build - user" )
}
2014-05-25 22:41:47 +04:00
func TestBuildRelativeWorkdir ( t * testing . T ) {
2014-05-31 16:43:32 +04:00
name := "testbuildrelativeworkdir"
expected := "/test2/test3"
defer deleteImages ( name )
_ , err := buildImage ( name ,
` FROM busybox
2014-05-25 22:41:47 +04:00
RUN [ "$PWD" = '/' ]
WORKDIR test1
RUN [ "$PWD" = ' / test1 ' ]
WORKDIR / test2
RUN [ "$PWD" = ' / test2 ' ]
WORKDIR test3
2014-05-31 16:43:32 +04:00
RUN [ "$PWD" = ' / test2 / test3 ' ] ` ,
true )
if err != nil {
t . Fatal ( err )
}
res , err := inspectField ( name , "Config.WorkingDir" )
if err != nil {
t . Fatal ( err )
}
if res != expected {
t . Fatalf ( "Workdir %s, expected %s" , res , expected )
}
2014-05-25 22:41:47 +04:00
logDone ( "build - relative workdir" )
}
2014-07-15 21:17:20 +04:00
func TestBuildWorkdirWithEnvVariables ( t * testing . T ) {
name := "testbuildworkdirwithenvvariables"
expected := "/test1/test2/$MISSING_VAR"
defer deleteImages ( name )
_ , err := buildImage ( name ,
` FROM busybox
ENV DIRPATH / test1
ENV SUBDIRNAME test2
WORKDIR $ DIRPATH
WORKDIR $ SUBDIRNAME / $ MISSING_VAR ` ,
true )
if err != nil {
t . Fatal ( err )
}
res , err := inspectField ( name , "Config.WorkingDir" )
if err != nil {
t . Fatal ( err )
}
if res != expected {
t . Fatalf ( "Workdir %s, expected %s" , res , expected )
}
logDone ( "build - workdir with env variables" )
}
2014-12-12 21:32:11 +03:00
func TestBuildRelativeCopy ( t * testing . T ) {
name := "testbuildrelativecopy"
defer deleteImages ( name )
dockerfile := `
FROM busybox
WORKDIR / test1
WORKDIR test2
RUN [ "$PWD" = ' / test1 / test2 ' ]
COPY foo . /
RUN [ "$(cat /test1/test2/foo)" = ' hello ' ]
ADD foo . / bar / baz
RUN [ "$(cat /test1/test2/bar/baz)" = ' hello ' ]
COPY foo . / bar / baz2
RUN [ "$(cat /test1/test2/bar/baz2)" = ' hello ' ]
WORKDIR . .
COPY foo . /
RUN [ "$(cat /test1/foo)" = ' hello ' ]
COPY foo / test3 /
RUN [ "$(cat /test3/foo)" = ' hello ' ]
WORKDIR / test4
COPY . .
RUN [ "$(cat /test4/foo)" = ' hello ' ]
WORKDIR / test5 / test6
COPY foo . . /
RUN [ "$(cat /test5/foo)" = ' hello ' ]
`
ctx , err := fakeContext ( dockerfile , map [ string ] string {
"foo" : "hello" ,
} )
defer ctx . Close ( )
if err != nil {
t . Fatal ( err )
}
_ , err = buildImageFromContext ( name , ctx , false )
if err != nil {
t . Fatal ( err )
}
logDone ( "build - relative copy/add" )
}
2014-05-26 23:09:33 +04:00
func TestBuildEnv ( t * testing . T ) {
2014-05-31 16:43:32 +04:00
name := "testbuildenv"
2014-08-13 14:07:41 +04:00
expected := "[PATH=/test:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin PORT=2375]"
2014-05-31 16:43:32 +04:00
defer deleteImages ( name )
_ , err := buildImage ( name ,
` FROM busybox
2014-08-13 14:07:41 +04:00
ENV PATH / test : $ PATH
2014-06-03 23:44:20 +04:00
ENV PORT 2375
RUN [ $ ( env | grep PORT ) = ' PORT = 2375 ' ] ` ,
2014-05-31 16:43:32 +04:00
true )
if err != nil {
t . Fatal ( err )
}
res , err := inspectField ( name , "Config.Env" )
if err != nil {
t . Fatal ( err )
}
if res != expected {
t . Fatalf ( "Env %s, expected %s" , res , expected )
}
2014-05-26 23:09:33 +04:00
logDone ( "build - env" )
}
2014-09-02 18:35:25 +04:00
func TestBuildContextCleanup ( t * testing . T ) {
2015-02-19 07:06:23 +03:00
testRequires ( t , SameHostDaemon )
2014-09-02 18:35:25 +04:00
name := "testbuildcontextcleanup"
defer deleteImages ( name )
entries , err := ioutil . ReadDir ( "/var/lib/docker/tmp" )
if err != nil {
t . Fatalf ( "failed to list contents of tmp dir: %s" , err )
}
_ , err = buildImage ( name ,
` FROM scratch
ENTRYPOINT [ "/bin/echo" ] ` ,
true )
if err != nil {
t . Fatal ( err )
}
entriesFinal , err := ioutil . ReadDir ( "/var/lib/docker/tmp" )
if err != nil {
t . Fatalf ( "failed to list contents of tmp dir: %s" , err )
}
if err = compareDirectoryEntries ( entries , entriesFinal ) ; err != nil {
t . Fatalf ( "context should have been deleted, but wasn't" )
}
logDone ( "build - verify context cleanup works properly" )
}
2014-09-15 17:01:23 +04:00
func TestBuildContextCleanupFailedBuild ( t * testing . T ) {
2015-02-19 07:06:23 +03:00
testRequires ( t , SameHostDaemon )
2014-09-15 17:01:23 +04:00
name := "testbuildcontextcleanup"
defer deleteImages ( name )
2014-11-17 19:05:49 +03:00
defer deleteAllContainers ( )
2014-09-15 17:01:23 +04:00
entries , err := ioutil . ReadDir ( "/var/lib/docker/tmp" )
if err != nil {
t . Fatalf ( "failed to list contents of tmp dir: %s" , err )
}
_ , err = buildImage ( name ,
` FROM scratch
RUN / non / existing / command ` ,
true )
if err == nil {
t . Fatalf ( "expected build to fail, but it didn't" )
}
entriesFinal , err := ioutil . ReadDir ( "/var/lib/docker/tmp" )
if err != nil {
t . Fatalf ( "failed to list contents of tmp dir: %s" , err )
}
if err = compareDirectoryEntries ( entries , entriesFinal ) ; err != nil {
t . Fatalf ( "context should have been deleted, but wasn't" )
}
2015-02-10 02:01:52 +03:00
logDone ( "build - verify context cleanup works properly after an unsuccessful build" )
2014-09-15 17:01:23 +04:00
}
2014-05-26 23:15:40 +04:00
func TestBuildCmd ( t * testing . T ) {
2014-05-31 16:43:32 +04:00
name := "testbuildcmd"
expected := "[/bin/echo Hello World]"
defer deleteImages ( name )
_ , err := buildImage ( name ,
` FROM scratch
CMD [ "/bin/echo" , "Hello World" ] ` ,
true )
if err != nil {
t . Fatal ( err )
}
res , err := inspectField ( name , "Config.Cmd" )
if err != nil {
t . Fatal ( err )
}
if res != expected {
t . Fatalf ( "Cmd %s, expected %s" , res , expected )
}
2014-05-26 23:15:40 +04:00
logDone ( "build - cmd" )
}
2014-05-26 23:23:46 +04:00
func TestBuildExpose ( t * testing . T ) {
2014-05-31 16:43:32 +04:00
name := "testbuildexpose"
2014-06-03 23:44:20 +04:00
expected := "map[2375/tcp:map[]]"
2014-05-31 16:43:32 +04:00
defer deleteImages ( name )
_ , err := buildImage ( name ,
` FROM scratch
2014-06-03 23:44:20 +04:00
EXPOSE 2375 ` ,
2014-05-31 16:43:32 +04:00
true )
if err != nil {
t . Fatal ( err )
}
res , err := inspectField ( name , "Config.ExposedPorts" )
if err != nil {
t . Fatal ( err )
}
if res != expected {
t . Fatalf ( "Exposed ports %s, expected %s" , res , expected )
}
2014-05-26 23:23:46 +04:00
logDone ( "build - expose" )
}
2014-11-13 06:14:15 +03:00
func TestBuildExposeMorePorts ( t * testing . T ) {
// start building docker file with a large number of ports
portList := make ( [ ] string , 50 )
line := make ( [ ] string , 100 )
expectedPorts := make ( [ ] int , len ( portList ) * len ( line ) )
for i := 0 ; i < len ( portList ) ; i ++ {
for j := 0 ; j < len ( line ) ; j ++ {
p := i * len ( line ) + j + 1
line [ j ] = strconv . Itoa ( p )
expectedPorts [ p - 1 ] = p
}
if i == len ( portList ) - 1 {
portList [ i ] = strings . Join ( line , " " )
} else {
portList [ i ] = strings . Join ( line , " " ) + ` \ `
}
}
dockerfile := ` FROM scratch
EXPOSE { { range . } } { { . } }
{ { end } } `
tmpl := template . Must ( template . New ( "dockerfile" ) . Parse ( dockerfile ) )
buf := bytes . NewBuffer ( nil )
tmpl . Execute ( buf , portList )
name := "testbuildexpose"
defer deleteImages ( name )
_ , err := buildImage ( name , buf . String ( ) , true )
if err != nil {
t . Fatal ( err )
}
// check if all the ports are saved inside Config.ExposedPorts
res , err := inspectFieldJSON ( name , "Config.ExposedPorts" )
if err != nil {
t . Fatal ( err )
}
var exposedPorts map [ string ] interface { }
if err := json . Unmarshal ( [ ] byte ( res ) , & exposedPorts ) ; err != nil {
t . Fatal ( err )
}
for _ , p := range expectedPorts {
ep := fmt . Sprintf ( "%d/tcp" , p )
if _ , ok := exposedPorts [ ep ] ; ! ok {
t . Errorf ( "Port(%s) is not exposed" , ep )
} else {
delete ( exposedPorts , ep )
}
}
if len ( exposedPorts ) != 0 {
t . Errorf ( "Unexpected extra exposed ports %v" , exposedPorts )
}
logDone ( "build - expose large number of ports" )
}
2014-11-12 17:13:47 +03:00
func TestBuildExposeOrder ( t * testing . T ) {
buildID := func ( name , exposed string ) string {
_ , err := buildImage ( name , fmt . Sprintf ( ` FROM scratch
EXPOSE % s ` , exposed ) , true )
if err != nil {
t . Fatal ( err )
}
id , err := inspectField ( name , "Id" )
if err != nil {
t . Fatal ( err )
}
return id
}
id1 := buildID ( "testbuildexpose1" , "80 2375" )
id2 := buildID ( "testbuildexpose2" , "2375 80" )
defer deleteImages ( "testbuildexpose1" , "testbuildexpose2" )
if id1 != id2 {
t . Errorf ( "EXPOSE should invalidate the cache only when ports actually changed" )
}
logDone ( "build - expose order" )
}
2015-02-08 02:04:22 +03:00
func TestBuildExposeUpperCaseProto ( t * testing . T ) {
name := "testbuildexposeuppercaseproto"
expected := "map[5678/udp:map[]]"
defer deleteImages ( name )
_ , err := buildImage ( name ,
` FROM scratch
EXPOSE 5678 / UDP ` ,
true )
if err != nil {
t . Fatal ( err )
}
res , err := inspectField ( name , "Config.ExposedPorts" )
if err != nil {
t . Fatal ( err )
}
if res != expected {
t . Fatalf ( "Exposed ports %s, expected %s" , res , expected )
}
logDone ( "build - expose port with upper case proto" )
}
2015-03-05 05:09:50 +03:00
func TestBuildExposeHostPort ( t * testing . T ) {
// start building docker file with ip:hostPort:containerPort
name := "testbuildexpose"
expected := "map[5678/tcp:map[]]"
defer deleteImages ( name )
_ , out , err := buildImageWithOut ( name ,
` FROM scratch
EXPOSE 192.168 .1 .2 : 2375 : 5678 ` ,
true )
if err != nil {
t . Fatal ( err )
}
if ! strings . Contains ( out , "to map host ports to container ports (ip:hostPort:containerPort) is deprecated." ) {
t . Fatal ( "Missing warning message" )
}
res , err := inspectField ( name , "Config.ExposedPorts" )
if err != nil {
t . Fatal ( err )
}
if res != expected {
t . Fatalf ( "Exposed ports %s, expected %s" , res , expected )
}
logDone ( "build - ignore exposing host's port" )
}
2014-10-24 04:23:25 +04:00
func TestBuildEmptyEntrypointInheritance ( t * testing . T ) {
name := "testbuildentrypointinheritance"
name2 := "testbuildentrypointinheritance2"
defer deleteImages ( name , name2 )
_ , err := buildImage ( name ,
` FROM busybox
ENTRYPOINT [ "/bin/echo" ] ` ,
true )
if err != nil {
t . Fatal ( err )
}
res , err := inspectField ( name , "Config.Entrypoint" )
if err != nil {
t . Fatal ( err )
}
expected := "[/bin/echo]"
if res != expected {
t . Fatalf ( "Entrypoint %s, expected %s" , res , expected )
}
_ , err = buildImage ( name2 ,
fmt . Sprintf ( ` FROM % s
ENTRYPOINT [ ] ` , name ) ,
true )
if err != nil {
t . Fatal ( err )
}
res , err = inspectField ( name2 , "Config.Entrypoint" )
if err != nil {
t . Fatal ( err )
}
expected = "[]"
if res != expected {
t . Fatalf ( "Entrypoint %s, expected %s" , res , expected )
}
logDone ( "build - empty entrypoint inheritance" )
}
2014-09-03 23:17:17 +04:00
func TestBuildEmptyEntrypoint ( t * testing . T ) {
2014-05-31 16:43:32 +04:00
name := "testbuildentrypoint"
defer deleteImages ( name )
2014-09-03 23:17:17 +04:00
expected := "[]"
2014-05-31 16:43:32 +04:00
_ , err := buildImage ( name ,
2014-09-03 23:17:17 +04:00
` FROM busybox
ENTRYPOINT [ ] ` ,
2014-05-31 16:43:32 +04:00
true )
if err != nil {
t . Fatal ( err )
}
res , err := inspectField ( name , "Config.Entrypoint" )
if err != nil {
t . Fatal ( err )
}
if res != expected {
t . Fatalf ( "Entrypoint %s, expected %s" , res , expected )
}
2014-09-02 00:33:06 +04:00
2014-09-03 23:17:17 +04:00
logDone ( "build - empty entrypoint" )
}
2014-09-02 00:33:06 +04:00
2014-09-03 23:17:17 +04:00
func TestBuildEntrypoint ( t * testing . T ) {
name := "testbuildentrypoint"
expected := "[/bin/echo]"
defer deleteImages ( name )
_ , err := buildImage ( name ,
` FROM scratch
ENTRYPOINT [ "/bin/echo" ] ` ,
2014-09-02 00:33:06 +04:00
true )
if err != nil {
t . Fatal ( err )
}
2014-09-03 23:17:17 +04:00
res , err := inspectField ( name , "Config.Entrypoint" )
2014-09-02 00:33:06 +04:00
if err != nil {
t . Fatal ( err )
}
if res != expected {
t . Fatalf ( "Entrypoint %s, expected %s" , res , expected )
}
2014-05-27 08:36:00 +04:00
logDone ( "build - entrypoint" )
}
2014-06-17 10:04:25 +04:00
// #6445 ensure ONBUILD triggers aren't committed to grandchildren
func TestBuildOnBuildLimitedInheritence ( t * testing . T ) {
2014-07-29 17:01:56 +04:00
var (
out2 , out3 string
)
{
name1 := "testonbuildtrigger1"
dockerfile1 := `
2014-06-17 10:04:25 +04:00
FROM busybox
RUN echo "GRANDPARENT"
ONBUILD RUN echo "ONBUILD PARENT"
2014-07-29 17:01:56 +04:00
`
ctx , err := fakeContext ( dockerfile1 , nil )
if err != nil {
t . Fatal ( err )
}
2014-11-20 20:38:41 +03:00
defer ctx . Close ( )
2014-06-17 10:04:25 +04:00
2014-07-29 17:01:56 +04:00
out1 , _ , err := dockerCmdInDir ( t , ctx . Dir , "build" , "-t" , name1 , "." )
2014-10-15 00:51:12 +04:00
if err != nil {
t . Fatalf ( "build failed to complete: %s, %v" , out1 , err )
}
2014-07-29 17:01:56 +04:00
defer deleteImages ( name1 )
2014-06-17 10:04:25 +04:00
}
2014-07-29 17:01:56 +04:00
{
name2 := "testonbuildtrigger2"
dockerfile2 := `
FROM testonbuildtrigger1
`
ctx , err := fakeContext ( dockerfile2 , nil )
if err != nil {
t . Fatal ( err )
}
2014-11-20 20:38:41 +03:00
defer ctx . Close ( )
2014-06-17 10:04:25 +04:00
2014-07-29 17:01:56 +04:00
out2 , _ , err = dockerCmdInDir ( t , ctx . Dir , "build" , "-t" , name2 , "." )
2014-10-15 00:51:12 +04:00
if err != nil {
t . Fatalf ( "build failed to complete: %s, %v" , out2 , err )
}
2014-07-29 17:01:56 +04:00
defer deleteImages ( name2 )
2014-06-17 10:04:25 +04:00
}
2014-07-29 17:01:56 +04:00
{
name3 := "testonbuildtrigger3"
dockerfile3 := `
FROM testonbuildtrigger2
`
ctx , err := fakeContext ( dockerfile3 , nil )
if err != nil {
t . Fatal ( err )
}
2014-11-20 20:38:41 +03:00
defer ctx . Close ( )
2014-06-17 10:04:25 +04:00
2014-07-29 17:01:56 +04:00
out3 , _ , err = dockerCmdInDir ( t , ctx . Dir , "build" , "-t" , name3 , "." )
2014-10-15 00:51:12 +04:00
if err != nil {
t . Fatalf ( "build failed to complete: %s, %v" , out3 , err )
}
2014-07-29 17:01:56 +04:00
defer deleteImages ( name3 )
}
2014-06-17 10:04:25 +04:00
// ONBUILD should be run in second build.
if ! strings . Contains ( out2 , "ONBUILD PARENT" ) {
t . Fatalf ( "ONBUILD instruction did not run in child of ONBUILD parent" )
}
// ONBUILD should *not* be run in third build.
if strings . Contains ( out3 , "ONBUILD PARENT" ) {
t . Fatalf ( "ONBUILD instruction ran in grandchild of ONBUILD parent" )
}
logDone ( "build - onbuild" )
}
2014-06-01 00:49:50 +04:00
func TestBuildWithCache ( t * testing . T ) {
name := "testbuildwithcache"
defer deleteImages ( name )
id1 , err := buildImage ( name ,
` FROM scratch
MAINTAINER dockerio
EXPOSE 5432
ENTRYPOINT [ "/bin/echo" ] ` ,
true )
if err != nil {
t . Fatal ( err )
}
id2 , err := buildImage ( name ,
` FROM scratch
MAINTAINER dockerio
EXPOSE 5432
ENTRYPOINT [ "/bin/echo" ] ` ,
true )
if err != nil {
t . Fatal ( err )
}
if id1 != id2 {
t . Fatal ( "The cache should have been used but hasn't." )
}
logDone ( "build - with cache" )
}
2014-02-25 20:17:48 +04:00
2014-06-01 00:49:50 +04:00
func TestBuildWithoutCache ( t * testing . T ) {
name := "testbuildwithoutcache"
2014-11-17 19:05:49 +03:00
name2 := "testbuildwithoutcache2"
defer deleteImages ( name , name2 )
2014-06-01 00:49:50 +04:00
id1 , err := buildImage ( name ,
` FROM scratch
MAINTAINER dockerio
EXPOSE 5432
ENTRYPOINT [ "/bin/echo" ] ` ,
true )
if err != nil {
t . Fatal ( err )
}
2014-11-17 19:05:49 +03:00
id2 , err := buildImage ( name2 ,
2014-06-01 00:49:50 +04:00
` FROM scratch
MAINTAINER dockerio
EXPOSE 5432
ENTRYPOINT [ "/bin/echo" ] ` ,
false )
if err != nil {
t . Fatal ( err )
}
if id1 == id2 {
t . Fatal ( "The cache should have been invalided but hasn't." )
}
logDone ( "build - without cache" )
}
2015-01-08 17:56:30 +03:00
func TestBuildConditionalCache ( t * testing . T ) {
name := "testbuildconditionalcache"
name2 := "testbuildconditionalcache2"
defer deleteImages ( name , name2 )
dockerfile := `
FROM busybox
ADD foo / tmp / `
ctx , err := fakeContext ( dockerfile , map [ string ] string {
"foo" : "hello" ,
} )
2015-02-25 11:53:43 +03:00
if err != nil {
t . Fatal ( err )
}
defer ctx . Close ( )
2015-01-08 17:56:30 +03:00
id1 , err := buildImageFromContext ( name , ctx , true )
if err != nil {
t . Fatalf ( "Error building #1: %s" , err )
}
if err := ctx . Add ( "foo" , "bye" ) ; err != nil {
t . Fatalf ( "Error modifying foo: %s" , err )
}
id2 , err := buildImageFromContext ( name , ctx , false )
if err != nil {
t . Fatalf ( "Error building #2: %s" , err )
}
if id2 == id1 {
t . Fatal ( "Should not have used the cache" )
}
id3 , err := buildImageFromContext ( name , ctx , true )
if err != nil {
t . Fatalf ( "Error building #3: %s" , err )
}
if id3 != id2 {
t . Fatal ( "Should have used the cache" )
}
logDone ( "build - conditional cache" )
}
2014-06-01 00:49:50 +04:00
func TestBuildADDLocalFileWithCache ( t * testing . T ) {
name := "testbuildaddlocalfilewithcache"
2014-11-17 19:05:49 +03:00
name2 := "testbuildaddlocalfilewithcache2"
defer deleteImages ( name , name2 )
2014-06-01 00:49:50 +04:00
dockerfile := `
FROM busybox
MAINTAINER dockerio
ADD foo / usr / lib / bla / bar
RUN [ "$(cat /usr/lib/bla/bar)" = "hello" ] `
ctx , err := fakeContext ( dockerfile , map [ string ] string {
"foo" : "hello" ,
} )
defer ctx . Close ( )
if err != nil {
t . Fatal ( err )
}
id1 , err := buildImageFromContext ( name , ctx , true )
if err != nil {
t . Fatal ( err )
}
2014-11-17 19:05:49 +03:00
id2 , err := buildImageFromContext ( name2 , ctx , true )
2014-06-01 00:49:50 +04:00
if err != nil {
t . Fatal ( err )
}
if id1 != id2 {
t . Fatal ( "The cache should have been used but hasn't." )
}
logDone ( "build - add local file with cache" )
}
2014-09-16 20:58:20 +04:00
func TestBuildADDMultipleLocalFileWithCache ( t * testing . T ) {
name := "testbuildaddmultiplelocalfilewithcache"
2014-11-17 19:05:49 +03:00
name2 := "testbuildaddmultiplelocalfilewithcache2"
defer deleteImages ( name , name2 )
2014-09-16 20:58:20 +04:00
dockerfile := `
FROM busybox
MAINTAINER dockerio
ADD foo Dockerfile / usr / lib / bla /
RUN [ "$(cat /usr/lib/bla/foo)" = "hello" ] `
ctx , err := fakeContext ( dockerfile , map [ string ] string {
"foo" : "hello" ,
} )
defer ctx . Close ( )
if err != nil {
t . Fatal ( err )
}
id1 , err := buildImageFromContext ( name , ctx , true )
if err != nil {
t . Fatal ( err )
}
2014-11-17 19:05:49 +03:00
id2 , err := buildImageFromContext ( name2 , ctx , true )
2014-09-16 20:58:20 +04:00
if err != nil {
t . Fatal ( err )
}
if id1 != id2 {
t . Fatal ( "The cache should have been used but hasn't." )
}
logDone ( "build - add multiple local files with cache" )
}
2014-06-01 00:49:50 +04:00
func TestBuildADDLocalFileWithoutCache ( t * testing . T ) {
name := "testbuildaddlocalfilewithoutcache"
2014-11-17 19:05:49 +03:00
name2 := "testbuildaddlocalfilewithoutcache2"
defer deleteImages ( name , name2 )
2014-06-01 00:49:50 +04:00
dockerfile := `
FROM busybox
MAINTAINER dockerio
ADD foo / usr / lib / bla / bar
RUN [ "$(cat /usr/lib/bla/bar)" = "hello" ] `
ctx , err := fakeContext ( dockerfile , map [ string ] string {
"foo" : "hello" ,
} )
defer ctx . Close ( )
if err != nil {
t . Fatal ( err )
}
id1 , err := buildImageFromContext ( name , ctx , true )
if err != nil {
t . Fatal ( err )
}
2014-11-17 19:05:49 +03:00
id2 , err := buildImageFromContext ( name2 , ctx , false )
2014-06-01 00:49:50 +04:00
if err != nil {
t . Fatal ( err )
}
if id1 == id2 {
t . Fatal ( "The cache should have been invalided but hasn't." )
}
logDone ( "build - add local file without cache" )
}
2014-09-23 23:08:42 +04:00
func TestBuildCopyDirButNotFile ( t * testing . T ) {
name := "testbuildcopydirbutnotfile"
2014-11-17 19:05:49 +03:00
name2 := "testbuildcopydirbutnotfile2"
defer deleteImages ( name , name2 )
2014-09-23 23:08:42 +04:00
dockerfile := `
FROM scratch
COPY dir / tmp / `
ctx , err := fakeContext ( dockerfile , map [ string ] string {
"dir/foo" : "hello" ,
} )
defer ctx . Close ( )
if err != nil {
t . Fatal ( err )
}
id1 , err := buildImageFromContext ( name , ctx , true )
if err != nil {
t . Fatal ( err )
}
// Check that adding file with similar name doesn't mess with cache
if err := ctx . Add ( "dir_file" , "hello2" ) ; err != nil {
t . Fatal ( err )
}
2014-11-17 19:05:49 +03:00
id2 , err := buildImageFromContext ( name2 , ctx , true )
2014-09-23 23:08:42 +04:00
if err != nil {
t . Fatal ( err )
}
if id1 != id2 {
t . Fatal ( "The cache should have been used but wasn't" )
}
logDone ( "build - add current directory but not file" )
}
2014-06-01 00:49:50 +04:00
func TestBuildADDCurrentDirWithCache ( t * testing . T ) {
name := "testbuildaddcurrentdirwithcache"
2014-11-17 19:05:49 +03:00
name2 := name + "2"
name3 := name + "3"
name4 := name + "4"
name5 := name + "5"
defer deleteImages ( name , name2 , name3 , name4 , name5 )
2014-06-01 00:49:50 +04:00
dockerfile := `
FROM scratch
MAINTAINER dockerio
ADD . / usr / lib / bla `
ctx , err := fakeContext ( dockerfile , map [ string ] string {
"foo" : "hello" ,
} )
defer ctx . Close ( )
if err != nil {
t . Fatal ( err )
}
id1 , err := buildImageFromContext ( name , ctx , true )
if err != nil {
t . Fatal ( err )
}
// Check that adding file invalidate cache of "ADD ."
if err := ctx . Add ( "bar" , "hello2" ) ; err != nil {
t . Fatal ( err )
}
2014-11-17 19:05:49 +03:00
id2 , err := buildImageFromContext ( name2 , ctx , true )
2014-06-01 00:49:50 +04:00
if err != nil {
t . Fatal ( err )
}
if id1 == id2 {
t . Fatal ( "The cache should have been invalided but hasn't." )
}
// Check that changing file invalidate cache of "ADD ."
if err := ctx . Add ( "foo" , "hello1" ) ; err != nil {
t . Fatal ( err )
}
2014-11-17 19:05:49 +03:00
id3 , err := buildImageFromContext ( name3 , ctx , true )
2014-06-01 00:49:50 +04:00
if err != nil {
t . Fatal ( err )
}
if id2 == id3 {
t . Fatal ( "The cache should have been invalided but hasn't." )
}
// Check that changing file to same content invalidate cache of "ADD ."
time . Sleep ( 1 * time . Second ) // wait second because of mtime precision
if err := ctx . Add ( "foo" , "hello1" ) ; err != nil {
t . Fatal ( err )
}
2014-11-17 19:05:49 +03:00
id4 , err := buildImageFromContext ( name4 , ctx , true )
2014-06-01 00:49:50 +04:00
if err != nil {
t . Fatal ( err )
}
if id3 == id4 {
t . Fatal ( "The cache should have been invalided but hasn't." )
}
2014-11-17 19:05:49 +03:00
id5 , err := buildImageFromContext ( name5 , ctx , true )
2014-06-01 00:49:50 +04:00
if err != nil {
t . Fatal ( err )
}
if id4 != id5 {
t . Fatal ( "The cache should have been used but hasn't." )
}
logDone ( "build - add current directory with cache" )
}
func TestBuildADDCurrentDirWithoutCache ( t * testing . T ) {
name := "testbuildaddcurrentdirwithoutcache"
2014-11-17 19:05:49 +03:00
name2 := "testbuildaddcurrentdirwithoutcache2"
defer deleteImages ( name , name2 )
2014-06-01 00:49:50 +04:00
dockerfile := `
FROM scratch
MAINTAINER dockerio
ADD . / usr / lib / bla `
ctx , err := fakeContext ( dockerfile , map [ string ] string {
"foo" : "hello" ,
} )
defer ctx . Close ( )
if err != nil {
t . Fatal ( err )
}
id1 , err := buildImageFromContext ( name , ctx , true )
if err != nil {
t . Fatal ( err )
}
2014-11-17 19:05:49 +03:00
id2 , err := buildImageFromContext ( name2 , ctx , false )
2014-06-01 00:49:50 +04:00
if err != nil {
t . Fatal ( err )
}
if id1 == id2 {
t . Fatal ( "The cache should have been invalided but hasn't." )
}
logDone ( "build - add current directory without cache" )
}
func TestBuildADDRemoteFileWithCache ( t * testing . T ) {
name := "testbuildaddremotefilewithcache"
defer deleteImages ( name )
server , err := fakeStorage ( map [ string ] string {
"baz" : "hello" ,
} )
if err != nil {
t . Fatal ( err )
}
defer server . Close ( )
2015-02-19 13:01:27 +03:00
2014-06-01 00:49:50 +04:00
id1 , err := buildImage ( name ,
fmt . Sprintf ( ` FROM scratch
MAINTAINER dockerio
2015-02-19 13:01:27 +03:00
ADD % s / baz / usr / lib / baz / quux ` , server . URL ( ) ) ,
2014-06-01 00:49:50 +04:00
true )
if err != nil {
t . Fatal ( err )
}
id2 , err := buildImage ( name ,
fmt . Sprintf ( ` FROM scratch
MAINTAINER dockerio
2015-02-19 13:01:27 +03:00
ADD % s / baz / usr / lib / baz / quux ` , server . URL ( ) ) ,
2014-06-01 00:49:50 +04:00
true )
if err != nil {
t . Fatal ( err )
}
if id1 != id2 {
t . Fatal ( "The cache should have been used but hasn't." )
}
logDone ( "build - add remote file with cache" )
}
func TestBuildADDRemoteFileWithoutCache ( t * testing . T ) {
name := "testbuildaddremotefilewithoutcache"
2014-11-17 19:05:49 +03:00
name2 := "testbuildaddremotefilewithoutcache2"
defer deleteImages ( name , name2 )
2014-06-01 00:49:50 +04:00
server , err := fakeStorage ( map [ string ] string {
"baz" : "hello" ,
} )
if err != nil {
t . Fatal ( err )
}
defer server . Close ( )
2015-02-19 13:01:27 +03:00
2014-06-01 00:49:50 +04:00
id1 , err := buildImage ( name ,
fmt . Sprintf ( ` FROM scratch
MAINTAINER dockerio
2015-02-19 13:01:27 +03:00
ADD % s / baz / usr / lib / baz / quux ` , server . URL ( ) ) ,
2014-06-01 00:49:50 +04:00
true )
if err != nil {
t . Fatal ( err )
}
2014-11-17 19:05:49 +03:00
id2 , err := buildImage ( name2 ,
2014-06-01 00:49:50 +04:00
fmt . Sprintf ( ` FROM scratch
MAINTAINER dockerio
2015-02-19 13:01:27 +03:00
ADD % s / baz / usr / lib / baz / quux ` , server . URL ( ) ) ,
2014-06-01 00:49:50 +04:00
false )
if err != nil {
t . Fatal ( err )
}
if id1 == id2 {
t . Fatal ( "The cache should have been invalided but hasn't." )
}
logDone ( "build - add remote file without cache" )
}
2014-10-22 22:16:42 +04:00
func TestBuildADDRemoteFileMTime ( t * testing . T ) {
name := "testbuildaddremotefilemtime"
2014-11-17 19:05:49 +03:00
name2 := name + "2"
name3 := name + "3"
name4 := name + "4"
defer deleteImages ( name , name2 , name3 , name4 )
2014-10-22 22:16:42 +04:00
2015-02-19 13:01:27 +03:00
files := map [ string ] string { "baz" : "hello" }
server , err := fakeStorage ( files )
2014-10-22 22:16:42 +04:00
if err != nil {
t . Fatal ( err )
}
defer server . Close ( )
ctx , err := fakeContext ( fmt . Sprintf ( ` FROM scratch
MAINTAINER dockerio
2015-02-19 13:01:27 +03:00
ADD % s / baz / usr / lib / baz / quux ` , server . URL ( ) ) , nil )
2014-10-22 22:16:42 +04:00
if err != nil {
t . Fatal ( err )
}
defer ctx . Close ( )
id1 , err := buildImageFromContext ( name , ctx , true )
if err != nil {
t . Fatal ( err )
}
2014-11-17 19:05:49 +03:00
id2 , err := buildImageFromContext ( name2 , ctx , true )
2014-10-22 22:16:42 +04:00
if err != nil {
t . Fatal ( err )
}
if id1 != id2 {
t . Fatal ( "The cache should have been used but wasn't - #1" )
}
2015-02-19 13:01:27 +03:00
// Now create a different server withsame contents (causes different mtim)
2014-10-22 22:16:42 +04:00
// This time the cache should not be used
2015-02-19 13:01:27 +03:00
// allow some time for clock to pass as mtime precision is only 1s
time . Sleep ( 2 * time . Second )
server2 , err := fakeStorage ( files )
2014-10-22 22:16:42 +04:00
if err != nil {
2015-02-19 13:01:27 +03:00
t . Fatal ( err )
2014-10-22 22:16:42 +04:00
}
2015-02-19 13:01:27 +03:00
defer server2 . Close ( )
2014-10-22 22:16:42 +04:00
2015-02-19 13:01:27 +03:00
ctx2 , err := fakeContext ( fmt . Sprintf ( ` FROM scratch
MAINTAINER dockerio
ADD % s / baz / usr / lib / baz / quux ` , server2 . URL ( ) ) , nil )
if err != nil {
t . Fatal ( err )
}
defer ctx2 . Close ( )
id3 , err := buildImageFromContext ( name3 , ctx2 , true )
2014-10-22 22:16:42 +04:00
if err != nil {
t . Fatal ( err )
}
if id1 == id3 {
t . Fatal ( "The cache should not have been used but was" )
}
// And for good measure do it again and make sure cache is used this time
2015-02-19 13:01:27 +03:00
id4 , err := buildImageFromContext ( name4 , ctx2 , true )
2014-10-22 22:16:42 +04:00
if err != nil {
t . Fatal ( err )
}
if id3 != id4 {
t . Fatal ( "The cache should have been used but wasn't - #2" )
}
logDone ( "build - add remote file testing mtime" )
}
2014-06-01 00:49:50 +04:00
func TestBuildADDLocalAndRemoteFilesWithCache ( t * testing . T ) {
name := "testbuildaddlocalandremotefilewithcache"
defer deleteImages ( name )
server , err := fakeStorage ( map [ string ] string {
"baz" : "hello" ,
} )
if err != nil {
t . Fatal ( err )
}
defer server . Close ( )
2015-02-19 13:01:27 +03:00
2014-06-01 00:49:50 +04:00
ctx , err := fakeContext ( fmt . Sprintf ( ` FROM scratch
MAINTAINER dockerio
ADD foo / usr / lib / bla / bar
2015-02-19 13:01:27 +03:00
ADD % s / baz / usr / lib / baz / quux ` , server . URL ( ) ) ,
2014-06-01 00:49:50 +04:00
map [ string ] string {
"foo" : "hello world" ,
} )
if err != nil {
t . Fatal ( err )
}
defer ctx . Close ( )
id1 , err := buildImageFromContext ( name , ctx , true )
if err != nil {
t . Fatal ( err )
}
id2 , err := buildImageFromContext ( name , ctx , true )
if err != nil {
t . Fatal ( err )
}
if id1 != id2 {
t . Fatal ( "The cache should have been used but hasn't." )
}
logDone ( "build - add local and remote file with cache" )
}
2014-05-10 02:26:41 +04:00
func testContextTar ( t * testing . T , compression archive . Compression ) {
2014-09-24 16:55:52 +04:00
ctx , err := fakeContext (
` FROM busybox
ADD foo / foo
CMD [ "cat" , "/foo" ] ` ,
map [ string ] string {
"foo" : "bar" ,
} ,
)
defer ctx . Close ( )
if err != nil {
t . Fatal ( err )
}
context , err := archive . Tar ( ctx . Dir , compression )
2014-05-10 02:26:41 +04:00
if err != nil {
t . Fatalf ( "failed to build context tar: %v" , err )
}
2014-09-24 16:55:52 +04:00
name := "contexttar"
buildCmd := exec . Command ( dockerBinary , "build" , "-t" , name , "-" )
defer deleteImages ( name )
2014-05-10 02:26:41 +04:00
buildCmd . Stdin = context
2014-10-15 00:51:12 +04:00
if out , _ , err := runCommandWithOutput ( buildCmd ) ; err != nil {
2014-05-10 02:26:41 +04:00
t . Fatalf ( "build failed to complete: %v %v" , out , err )
}
logDone ( fmt . Sprintf ( "build - build an image with a context tar, compression: %v" , compression ) )
}
2014-09-19 16:33:57 +04:00
func TestBuildContextTarGzip ( t * testing . T ) {
2014-05-10 02:26:41 +04:00
testContextTar ( t , archive . Gzip )
}
2014-09-19 16:33:57 +04:00
func TestBuildContextTarNoCompression ( t * testing . T ) {
2014-05-10 02:26:41 +04:00
testContextTar ( t , archive . Uncompressed )
}
2014-08-30 15:34:09 +04:00
func TestBuildNoContext ( t * testing . T ) {
2014-05-10 02:26:41 +04:00
buildCmd := exec . Command ( dockerBinary , "build" , "-t" , "nocontext" , "-" )
buildCmd . Stdin = strings . NewReader ( "FROM busybox\nCMD echo ok\n" )
2014-10-15 00:51:12 +04:00
if out , _ , err := runCommandWithOutput ( buildCmd ) ; err != nil {
2014-05-10 02:26:41 +04:00
t . Fatalf ( "build failed to complete: %v %v" , out , err )
}
2014-11-24 18:32:38 +03:00
if out , _ , err := dockerCmd ( t , "run" , "--rm" , "nocontext" ) ; out != "ok\n" || err != nil {
2014-05-10 02:26:41 +04:00
t . Fatalf ( "run produced invalid output: %q, expected %q" , out , "ok" )
}
deleteImages ( "nocontext" )
logDone ( "build - build an image with no context" )
}
2014-06-03 01:46:28 +04:00
// TODO: TestCaching
2014-06-01 00:49:50 +04:00
func TestBuildADDLocalAndRemoteFilesWithoutCache ( t * testing . T ) {
name := "testbuildaddlocalandremotefilewithoutcache"
2014-11-17 19:05:49 +03:00
name2 := "testbuildaddlocalandremotefilewithoutcache2"
defer deleteImages ( name , name2 )
2014-06-01 00:49:50 +04:00
server , err := fakeStorage ( map [ string ] string {
"baz" : "hello" ,
} )
if err != nil {
t . Fatal ( err )
}
defer server . Close ( )
2015-02-19 13:01:27 +03:00
2014-06-01 00:49:50 +04:00
ctx , err := fakeContext ( fmt . Sprintf ( ` FROM scratch
MAINTAINER dockerio
ADD foo / usr / lib / bla / bar
2015-02-19 13:01:27 +03:00
ADD % s / baz / usr / lib / baz / quux ` , server . URL ( ) ) ,
2014-06-01 00:49:50 +04:00
map [ string ] string {
"foo" : "hello world" ,
} )
if err != nil {
t . Fatal ( err )
}
defer ctx . Close ( )
id1 , err := buildImageFromContext ( name , ctx , true )
if err != nil {
t . Fatal ( err )
}
2014-11-17 19:05:49 +03:00
id2 , err := buildImageFromContext ( name2 , ctx , false )
2014-06-01 00:49:50 +04:00
if err != nil {
t . Fatal ( err )
}
if id1 == id2 {
t . Fatal ( "The cache should have been invalided but hasn't." )
}
logDone ( "build - add local and remote file without cache" )
}
2014-06-03 01:46:28 +04:00
func TestBuildWithVolumeOwnership ( t * testing . T ) {
name := "testbuildimg"
defer deleteImages ( name )
_ , err := buildImage ( name ,
` FROM busybox : latest
RUN mkdir / test && chown daemon : daemon / test && chmod 0600 / test
VOLUME / test ` ,
true )
if err != nil {
t . Fatal ( err )
}
cmd := exec . Command ( dockerBinary , "run" , "--rm" , "testbuildimg" , "ls" , "-la" , "/test" )
out , _ , err := runCommandWithOutput ( cmd )
if err != nil {
2014-08-28 18:18:08 +04:00
t . Fatal ( out , err )
2014-06-03 01:46:28 +04:00
}
if expected := "drw-------" ; ! strings . Contains ( out , expected ) {
t . Fatalf ( "expected %s received %s" , expected , out )
}
if expected := "daemon daemon" ; ! strings . Contains ( out , expected ) {
t . Fatalf ( "expected %s received %s" , expected , out )
}
logDone ( "build - volume ownership" )
}
2014-06-17 10:08:14 +04:00
// testing #1405 - config.Cmd does not get cleaned up if
// utilizing cache
func TestBuildEntrypointRunCleanup ( t * testing . T ) {
name := "testbuildcmdcleanup"
defer deleteImages ( name )
if _ , err := buildImage ( name ,
` FROM busybox
RUN echo "hello" ` ,
true ) ; err != nil {
t . Fatal ( err )
}
ctx , err := fakeContext ( ` FROM busybox
RUN echo "hello"
ADD foo / foo
ENTRYPOINT [ "/bin/echo" ] ` ,
map [ string ] string {
"foo" : "hello" ,
} )
defer ctx . Close ( )
if err != nil {
t . Fatal ( err )
}
if _ , err := buildImageFromContext ( name , ctx , true ) ; err != nil {
t . Fatal ( err )
}
res , err := inspectField ( name , "Config.Cmd" )
if err != nil {
t . Fatal ( err )
}
2014-07-08 21:37:20 +04:00
// Cmd must be cleaned up
if expected := "<no value>" ; res != expected {
2014-06-17 10:08:14 +04:00
t . Fatalf ( "Cmd %s, expected %s" , res , expected )
}
logDone ( "build - cleanup cmd after RUN" )
}
2014-06-17 10:26:42 +04:00
2014-08-06 22:24:00 +04:00
func TestBuildForbiddenContextPath ( t * testing . T ) {
2014-06-17 10:26:42 +04:00
name := "testbuildforbidpath"
defer deleteImages ( name )
ctx , err := fakeContext ( ` FROM scratch
ADD . . / . . / test /
` ,
map [ string ] string {
"test.txt" : "test1" ,
"other.txt" : "other" ,
} )
defer ctx . Close ( )
if err != nil {
t . Fatal ( err )
}
2014-08-06 22:24:00 +04:00
expected := "Forbidden path outside the build context: ../../ "
if _ , err := buildImageFromContext ( name , ctx , true ) ; err == nil || ! strings . Contains ( err . Error ( ) , expected ) {
t . Fatalf ( "Wrong error: (should contain \"%s\") got:\n%v" , expected , err )
2014-06-17 10:26:42 +04:00
}
2014-08-06 22:24:00 +04:00
2014-06-17 10:26:42 +04:00
logDone ( "build - forbidden context path" )
}
2014-06-17 10:35:29 +04:00
func TestBuildADDFileNotFound ( t * testing . T ) {
name := "testbuildaddnotfound"
defer deleteImages ( name )
ctx , err := fakeContext ( ` FROM scratch
ADD foo / usr / local / bar ` ,
map [ string ] string { "bar" : "hello" } )
defer ctx . Close ( )
if err != nil {
t . Fatal ( err )
}
if _ , err := buildImageFromContext ( name , ctx , true ) ; err != nil {
if ! strings . Contains ( err . Error ( ) , "foo: no such file or directory" ) {
t . Fatalf ( "Wrong error %v, must be about missing foo file or directory" , err )
}
} else {
t . Fatal ( "Error must not be nil" )
}
logDone ( "build - add file not found" )
}
2014-06-17 10:50:51 +04:00
func TestBuildInheritance ( t * testing . T ) {
name := "testbuildinheritance"
defer deleteImages ( name )
_ , err := buildImage ( name ,
` FROM scratch
EXPOSE 2375 ` ,
true )
if err != nil {
t . Fatal ( err )
}
ports1 , err := inspectField ( name , "Config.ExposedPorts" )
if err != nil {
t . Fatal ( err )
}
_ , err = buildImage ( name ,
fmt . Sprintf ( ` FROM % s
ENTRYPOINT [ "/bin/echo" ] ` , name ) ,
true )
if err != nil {
t . Fatal ( err )
}
res , err := inspectField ( name , "Config.Entrypoint" )
if err != nil {
t . Fatal ( err )
}
if expected := "[/bin/echo]" ; res != expected {
t . Fatalf ( "Entrypoint %s, expected %s" , res , expected )
}
ports2 , err := inspectField ( name , "Config.ExposedPorts" )
if err != nil {
t . Fatal ( err )
}
if ports1 != ports2 {
t . Fatalf ( "Ports must be same: %s != %s" , ports1 , ports2 )
}
logDone ( "build - inheritance" )
}
2014-06-17 10:57:32 +04:00
func TestBuildFails ( t * testing . T ) {
name := "testbuildfails"
defer deleteImages ( name )
2014-11-17 19:05:49 +03:00
defer deleteAllContainers ( )
2014-06-17 10:57:32 +04:00
_ , err := buildImage ( name ,
` FROM busybox
RUN sh - c "exit 23" ` ,
true )
if err != nil {
if ! strings . Contains ( err . Error ( ) , "returned a non-zero code: 23" ) {
t . Fatalf ( "Wrong error %v, must be about non-zero code 23" , err )
}
} else {
t . Fatal ( "Error must not be nil" )
}
2015-02-10 02:01:52 +03:00
logDone ( "build - unsuccessful" )
2014-06-17 10:57:32 +04:00
}
2014-06-17 11:04:07 +04:00
func TestBuildFailsDockerfileEmpty ( t * testing . T ) {
name := "testbuildfails"
defer deleteImages ( name )
_ , err := buildImage ( name , ` ` , true )
if err != nil {
if ! strings . Contains ( err . Error ( ) , "Dockerfile cannot be empty" ) {
t . Fatalf ( "Wrong error %v, must be about empty Dockerfile" , err )
}
} else {
t . Fatal ( "Error must not be nil" )
}
2015-02-10 02:01:52 +03:00
logDone ( "build - unsuccessful with empty dockerfile" )
2014-06-17 11:04:07 +04:00
}
2014-06-17 11:14:45 +04:00
func TestBuildOnBuild ( t * testing . T ) {
name := "testbuildonbuild"
defer deleteImages ( name )
_ , err := buildImage ( name ,
` FROM busybox
ONBUILD RUN touch foobar ` ,
true )
if err != nil {
t . Fatal ( err )
}
_ , err = buildImage ( name ,
fmt . Sprintf ( ` FROM % s
RUN [ - f foobar ] ` , name ) ,
true )
if err != nil {
t . Fatal ( err )
}
logDone ( "build - onbuild" )
}
2014-06-17 11:24:47 +04:00
func TestBuildOnBuildForbiddenChained ( t * testing . T ) {
name := "testbuildonbuildforbiddenchained"
defer deleteImages ( name )
_ , err := buildImage ( name ,
` FROM busybox
ONBUILD ONBUILD RUN touch foobar ` ,
true )
if err != nil {
if ! strings . Contains ( err . Error ( ) , "Chaining ONBUILD via `ONBUILD ONBUILD` isn't allowed" ) {
t . Fatalf ( "Wrong error %v, must be about chaining ONBUILD" , err )
}
} else {
t . Fatal ( "Error must not be nil" )
}
logDone ( "build - onbuild forbidden chained" )
}
2014-06-17 11:36:45 +04:00
func TestBuildOnBuildForbiddenFrom ( t * testing . T ) {
name := "testbuildonbuildforbiddenfrom"
defer deleteImages ( name )
_ , err := buildImage ( name ,
` FROM busybox
ONBUILD FROM scratch ` ,
true )
if err != nil {
if ! strings . Contains ( err . Error ( ) , "FROM isn't allowed as an ONBUILD trigger" ) {
t . Fatalf ( "Wrong error %v, must be about FROM forbidden" , err )
}
} else {
t . Fatal ( "Error must not be nil" )
}
logDone ( "build - onbuild forbidden from" )
}
2014-06-17 11:39:47 +04:00
func TestBuildOnBuildForbiddenMaintainer ( t * testing . T ) {
name := "testbuildonbuildforbiddenmaintainer"
defer deleteImages ( name )
_ , err := buildImage ( name ,
` FROM busybox
ONBUILD MAINTAINER docker . io ` ,
true )
if err != nil {
if ! strings . Contains ( err . Error ( ) , "MAINTAINER isn't allowed as an ONBUILD trigger" ) {
t . Fatalf ( "Wrong error %v, must be about MAINTAINER forbidden" , err )
}
} else {
t . Fatal ( "Error must not be nil" )
}
logDone ( "build - onbuild forbidden maintainer" )
}
2014-06-17 11:49:07 +04:00
// gh #2446
func TestBuildAddToSymlinkDest ( t * testing . T ) {
name := "testbuildaddtosymlinkdest"
defer deleteImages ( name )
ctx , err := fakeContext ( ` FROM busybox
RUN mkdir / foo
RUN ln - s / foo / bar
ADD foo / bar /
RUN [ - f / bar / foo ]
RUN [ - f / foo / foo ] ` ,
map [ string ] string {
"foo" : "hello" ,
} )
if err != nil {
t . Fatal ( err )
}
defer ctx . Close ( )
if _ , err := buildImageFromContext ( name , ctx , true ) ; err != nil {
t . Fatal ( err )
}
logDone ( "build - add to symlink destination" )
}
2014-06-25 10:54:53 +04:00
func TestBuildEscapeWhitespace ( t * testing . T ) {
name := "testbuildescaping"
defer deleteImages ( name )
_ , err := buildImage ( name , `
FROM busybox
MAINTAINER " Docker \
IO < io @ \
docker . com > "
` , true )
res , err := inspectField ( name , "Author" )
if err != nil {
t . Fatal ( err )
}
2014-12-11 15:56:21 +03:00
if res != "\"Docker IO <io@docker.com>\"" {
t . Fatalf ( "Parsed string did not match the escaped string. Got: %q" , res )
2014-06-25 10:54:53 +04:00
}
logDone ( "build - validate escaping whitespace" )
}
2014-02-15 22:38:48 +04:00
2014-12-11 15:56:21 +03:00
func TestBuildVerifyIntString ( t * testing . T ) {
// Verify that strings that look like ints are still passed as strings
name := "testbuildstringing"
defer deleteImages ( name )
_ , err := buildImage ( name , `
FROM busybox
MAINTAINER 123
` , true )
out , rc , err := runCommandWithOutput ( exec . Command ( dockerBinary , "inspect" , name ) )
if rc != 0 || err != nil {
t . Fatalf ( "Unexcepted error from inspect: rc: %v err: %v" , rc , err )
}
if ! strings . Contains ( out , "\"123\"" ) {
t . Fatalf ( "Output does not contain the int as a string:\n%s" , out )
}
logDone ( "build - verify int/strings as strings" )
}
2014-09-19 16:33:57 +04:00
func TestBuildDockerignore ( t * testing . T ) {
2014-02-15 22:38:48 +04:00
name := "testbuilddockerignore"
defer deleteImages ( name )
dockerfile := `
FROM busybox
ADD . / bla
RUN [ [ - f / bla / src / x . go ] ]
RUN [ [ - f / bla / Makefile ] ]
RUN [ [ ! - e / bla / src / _vendor ] ]
RUN [ [ ! - e / bla / . gitignore ] ]
RUN [ [ ! - e / bla / README . md ] ]
RUN [ [ ! - e / bla / . git ] ] `
ctx , err := fakeContext ( dockerfile , map [ string ] string {
"Makefile" : "all:" ,
".git/HEAD" : "ref: foo" ,
"src/x.go" : "package main" ,
"src/_vendor/v.go" : "package main" ,
".gitignore" : "" ,
"README.md" : "readme" ,
".dockerignore" : ".git\npkg\n.gitignore\nsrc/_vendor\n*.md" ,
} )
defer ctx . Close ( )
if err != nil {
t . Fatal ( err )
}
if _ , err := buildImageFromContext ( name , ctx , true ) ; err != nil {
t . Fatal ( err )
}
logDone ( "build - test .dockerignore" )
}
2014-10-24 01:54:35 +04:00
func TestBuildDockerignoreCleanPaths ( t * testing . T ) {
name := "testbuilddockerignorecleanpaths"
defer deleteImages ( name )
dockerfile := `
FROM busybox
ADD . / tmp /
RUN ( ! ls / tmp / foo ) && ( ! ls / tmp / foo2 ) && ( ! ls / tmp / dir1 / foo ) `
ctx , err := fakeContext ( dockerfile , map [ string ] string {
"foo" : "foo" ,
"foo2" : "foo2" ,
"dir1/foo" : "foo in dir1" ,
".dockerignore" : "./foo\ndir1//foo\n./dir1/../foo2" ,
} )
if err != nil {
t . Fatal ( err )
}
defer ctx . Close ( )
if _ , err := buildImageFromContext ( name , ctx , true ) ; err != nil {
t . Fatal ( err )
}
logDone ( "build - test .dockerignore with clean paths" )
}
2014-09-19 16:33:57 +04:00
func TestBuildDockerignoringDockerfile ( t * testing . T ) {
2014-02-15 22:38:48 +04:00
name := "testbuilddockerignoredockerfile"
defer deleteImages ( name )
dockerfile := `
2014-10-24 01:30:11 +04:00
FROM busybox
ADD . / tmp /
RUN ! ls / tmp / Dockerfile
RUN ls / tmp / . dockerignore `
2014-02-15 22:38:48 +04:00
ctx , err := fakeContext ( dockerfile , map [ string ] string {
2014-10-24 01:30:11 +04:00
"Dockerfile" : dockerfile ,
2014-02-15 22:38:48 +04:00
".dockerignore" : "Dockerfile\n" ,
} )
if err != nil {
t . Fatal ( err )
}
2015-02-25 11:53:43 +03:00
defer ctx . Close ( )
2014-10-24 01:30:11 +04:00
if _ , err = buildImageFromContext ( name , ctx , true ) ; err != nil {
t . Fatalf ( "Didn't ignore Dockerfile correctly:%s" , err )
2014-02-15 22:38:48 +04:00
}
2014-10-24 01:54:35 +04:00
// now try it with ./Dockerfile
ctx . Add ( ".dockerignore" , "./Dockerfile\n" )
2014-10-24 01:30:11 +04:00
if _ , err = buildImageFromContext ( name , ctx , true ) ; err != nil {
t . Fatalf ( "Didn't ignore ./Dockerfile correctly:%s" , err )
2014-10-24 01:54:35 +04:00
}
2014-02-15 22:38:48 +04:00
logDone ( "build - test .dockerignore of Dockerfile" )
}
2014-07-06 15:36:34 +04:00
2014-09-11 18:42:17 +04:00
func TestBuildDockerignoringRenamedDockerfile ( t * testing . T ) {
name := "testbuilddockerignoredockerfile"
defer deleteImages ( name )
dockerfile := `
FROM busybox
ADD . / tmp /
RUN ls / tmp / Dockerfile
RUN ! ls / tmp / MyDockerfile
RUN ls / tmp / . dockerignore `
ctx , err := fakeContext ( dockerfile , map [ string ] string {
"Dockerfile" : "Should not use me" ,
"MyDockerfile" : dockerfile ,
".dockerignore" : "MyDockerfile\n" ,
} )
if err != nil {
t . Fatal ( err )
}
2015-02-25 11:53:43 +03:00
defer ctx . Close ( )
2014-09-11 18:42:17 +04:00
if _ , err = buildImageFromContext ( name , ctx , true ) ; err != nil {
t . Fatalf ( "Didn't ignore MyDockerfile correctly:%s" , err )
}
// now try it with ./MyDockerfile
ctx . Add ( ".dockerignore" , "./MyDockerfile\n" )
if _ , err = buildImageFromContext ( name , ctx , true ) ; err != nil {
t . Fatalf ( "Didn't ignore ./MyDockerfile correctly:%s" , err )
}
logDone ( "build - test .dockerignore of renamed Dockerfile" )
}
2014-10-24 01:30:11 +04:00
func TestBuildDockerignoringDockerignore ( t * testing . T ) {
name := "testbuilddockerignoredockerignore"
defer deleteImages ( name )
dockerfile := `
FROM busybox
ADD . / tmp /
RUN ! ls / tmp / . dockerignore
RUN ls / tmp / Dockerfile `
ctx , err := fakeContext ( dockerfile , map [ string ] string {
"Dockerfile" : dockerfile ,
".dockerignore" : ".dockerignore\n" ,
} )
defer ctx . Close ( )
if err != nil {
t . Fatal ( err )
}
if _ , err = buildImageFromContext ( name , ctx , true ) ; err != nil {
t . Fatalf ( "Didn't ignore .dockerignore correctly:%s" , err )
}
logDone ( "build - test .dockerignore of .dockerignore" )
}
func TestBuildDockerignoreTouchDockerfile ( t * testing . T ) {
var id1 string
var id2 string
name := "testbuilddockerignoretouchdockerfile"
defer deleteImages ( name )
dockerfile := `
FROM busybox
ADD . / tmp / `
ctx , err := fakeContext ( dockerfile , map [ string ] string {
"Dockerfile" : dockerfile ,
".dockerignore" : "Dockerfile\n" ,
} )
defer ctx . Close ( )
if err != nil {
t . Fatal ( err )
}
if id1 , err = buildImageFromContext ( name , ctx , true ) ; err != nil {
t . Fatalf ( "Didn't build it correctly:%s" , err )
}
if id2 , err = buildImageFromContext ( name , ctx , true ) ; err != nil {
t . Fatalf ( "Didn't build it correctly:%s" , err )
}
if id1 != id2 {
t . Fatalf ( "Didn't use the cache - 1" )
}
// Now make sure touching Dockerfile doesn't invalidate the cache
if err = ctx . Add ( "Dockerfile" , dockerfile + "\n# hi" ) ; err != nil {
t . Fatalf ( "Didn't add Dockerfile: %s" , err )
}
if id2 , err = buildImageFromContext ( name , ctx , true ) ; err != nil {
t . Fatalf ( "Didn't build it correctly:%s" , err )
}
if id1 != id2 {
t . Fatalf ( "Didn't use the cache - 2" )
}
// One more time but just 'touch' it instead of changing the content
if err = ctx . Add ( "Dockerfile" , dockerfile + "\n# hi" ) ; err != nil {
t . Fatalf ( "Didn't add Dockerfile: %s" , err )
}
if id2 , err = buildImageFromContext ( name , ctx , true ) ; err != nil {
t . Fatalf ( "Didn't build it correctly:%s" , err )
}
if id1 != id2 {
t . Fatalf ( "Didn't use the cache - 3" )
}
logDone ( "build - test .dockerignore touch dockerfile" )
}
2014-09-19 16:33:57 +04:00
func TestBuildDockerignoringWholeDir ( t * testing . T ) {
2014-07-18 09:35:54 +04:00
name := "testbuilddockerignorewholedir"
defer deleteImages ( name )
dockerfile := `
FROM busybox
COPY . /
RUN [ [ ! - e / . gitignore ] ]
RUN [ [ - f / Makefile ] ] `
ctx , err := fakeContext ( dockerfile , map [ string ] string {
"Dockerfile" : "FROM scratch" ,
"Makefile" : "all:" ,
".dockerignore" : ".*\n" ,
} )
defer ctx . Close ( )
if err != nil {
t . Fatal ( err )
}
if _ , err = buildImageFromContext ( name , ctx , true ) ; err != nil {
t . Fatal ( err )
}
logDone ( "build - test .dockerignore whole dir with .*" )
}
2014-07-06 15:36:34 +04:00
func TestBuildLineBreak ( t * testing . T ) {
name := "testbuildlinebreak"
defer deleteImages ( name )
_ , err := buildImage ( name ,
` FROM busybox
RUN sh - c ' echo root : testpass \
> / tmp / passwd '
RUN mkdir - p / var / run / sshd
RUN [ "$(cat /tmp/passwd)" = "root:testpass" ]
RUN [ "$(ls -d /var/run/sshd)" = "/var/run/sshd" ] ` ,
true )
if err != nil {
t . Fatal ( err )
}
logDone ( "build - line break with \\" )
}
func TestBuildEOLInLine ( t * testing . T ) {
name := "testbuildeolinline"
defer deleteImages ( name )
_ , err := buildImage ( name ,
` FROM busybox
RUN sh - c ' echo root : testpass > / tmp / passwd '
RUN echo "foo \n bar" ; echo "baz"
RUN mkdir - p / var / run / sshd
RUN [ "$(cat /tmp/passwd)" = "root:testpass" ]
RUN [ "$(ls -d /var/run/sshd)" = "/var/run/sshd" ] ` ,
true )
if err != nil {
t . Fatal ( err )
}
logDone ( "build - end of line in dockerfile instruction" )
}
func TestBuildCommentsShebangs ( t * testing . T ) {
name := "testbuildcomments"
defer deleteImages ( name )
_ , err := buildImage ( name ,
` FROM busybox
# This is an ordinary comment .
RUN { echo ' # ! / bin / sh ' ; echo ' echo hello world ' ; } > / hello . sh
RUN [ ! - x / hello . sh ]
# comment with line break \
RUN chmod + x / hello . sh
RUN [ - x / hello . sh ]
RUN [ "$(cat /hello.sh)" = $ ' # ! / bin / sh \ necho hello world ' ]
RUN [ "$(/hello.sh)" = "hello world" ] ` ,
true )
if err != nil {
t . Fatal ( err )
}
logDone ( "build - comments and shebangs" )
}
func TestBuildUsersAndGroups ( t * testing . T ) {
name := "testbuildusers"
defer deleteImages ( name )
_ , err := buildImage ( name ,
` FROM busybox
# Make sure our defaults work
RUN [ "$(id -u):$(id -g)/$(id -un):$(id -gn)" = ' 0 : 0 / root : root ' ]
# 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 )
USER root
RUN [ "$(id -G):$(id -Gn)" = ' 0 10 : root wheel ' ]
# Setup dockerio user and group
RUN echo ' dockerio : x : 1001 : 1001 : : / bin : / bin / false ' >> / etc / passwd
RUN echo ' dockerio : x : 1001 : ' >> / etc / group
# Make sure we can switch to our user and all the information is exactly as we expect it to be
USER dockerio
RUN id - G
RUN id - Gn
RUN [ "$(id -u):$(id -g)/$(id -un):$(id -gn)/$(id -G):$(id -Gn)" = ' 1001 : 1001 / dockerio : dockerio / 1001 : dockerio ' ]
# Switch back to root and double check that worked exactly as we might expect it to
USER root
RUN [ "$(id -u):$(id -g)/$(id -un):$(id -gn)/$(id -G):$(id -Gn)" = ' 0 : 0 / root : root / 0 10 : root wheel ' ]
# Add a "supplementary" group for our dockerio user
RUN echo ' supplementary : x : 1002 : dockerio ' >> / etc / group
# ... and then go verify that we get it like we expect
USER dockerio
RUN [ "$(id -u):$(id -g)/$(id -un):$(id -gn)/$(id -G):$(id -Gn)" = ' 1001 : 1001 / dockerio : dockerio / 1001 1002 : dockerio supplementary ' ]
USER 1001
RUN [ "$(id -u):$(id -g)/$(id -un):$(id -gn)/$(id -G):$(id -Gn)" = ' 1001 : 1001 / dockerio : dockerio / 1001 1002 : dockerio supplementary ' ]
# super test the new "user:group" syntax
USER dockerio : dockerio
RUN [ "$(id -u):$(id -g)/$(id -un):$(id -gn)/$(id -G):$(id -Gn)" = ' 1001 : 1001 / dockerio : dockerio / 1001 : dockerio ' ]
USER 1001 : dockerio
RUN [ "$(id -u):$(id -g)/$(id -un):$(id -gn)/$(id -G):$(id -Gn)" = ' 1001 : 1001 / dockerio : dockerio / 1001 : dockerio ' ]
USER dockerio : 1001
RUN [ "$(id -u):$(id -g)/$(id -un):$(id -gn)/$(id -G):$(id -Gn)" = ' 1001 : 1001 / dockerio : dockerio / 1001 : dockerio ' ]
USER 1001 : 1001
RUN [ "$(id -u):$(id -g)/$(id -un):$(id -gn)/$(id -G):$(id -Gn)" = ' 1001 : 1001 / dockerio : dockerio / 1001 : dockerio ' ]
USER dockerio : supplementary
RUN [ "$(id -u):$(id -g)/$(id -un):$(id -gn)/$(id -G):$(id -Gn)" = ' 1001 : 1002 / dockerio : supplementary / 1002 : supplementary ' ]
USER dockerio : 1002
RUN [ "$(id -u):$(id -g)/$(id -un):$(id -gn)/$(id -G):$(id -Gn)" = ' 1001 : 1002 / dockerio : supplementary / 1002 : supplementary ' ]
USER 1001 : supplementary
RUN [ "$(id -u):$(id -g)/$(id -un):$(id -gn)/$(id -G):$(id -Gn)" = ' 1001 : 1002 / dockerio : supplementary / 1002 : supplementary ' ]
USER 1001 : 1002
RUN [ "$(id -u):$(id -g)/$(id -un):$(id -gn)/$(id -G):$(id -Gn)" = ' 1001 : 1002 / dockerio : supplementary / 1002 : supplementary ' ]
# make sure unknown uid / gid still works properly
USER 1042 : 1043
RUN [ "$(id -u):$(id -g)/$(id -un):$(id -gn)/$(id -G):$(id -Gn)" = ' 1042 : 1043 / 1042 : 1043 / 1043 : 1043 ' ] ` ,
true )
if err != nil {
t . Fatal ( err )
}
logDone ( "build - users and groups" )
}
func TestBuildEnvUsage ( t * testing . T ) {
name := "testbuildenvusage"
defer deleteImages ( name )
dockerfile := ` FROM busybox
2014-10-25 22:29:18 +04:00
ENV HOME / root
2014-08-13 14:07:41 +04:00
ENV PATH $ HOME / bin : $ PATH
ENV PATH / tmp : $ PATH
RUN [ "$PATH" = "/tmp:$HOME/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" ]
2014-07-06 15:36:34 +04:00
ENV FOO / foo / baz
ENV BAR / bar
ENV BAZ $ BAR
ENV FOOPATH $ PATH : $ FOO
RUN [ "$BAR" = "$BAZ" ]
RUN [ "$FOOPATH" = "$PATH:/foo/baz" ]
ENV FROM hello / docker / world
ENV TO / docker / world / hello
ADD $ FROM $ TO
2014-08-13 14:07:41 +04:00
RUN [ "$(cat $TO)" = "hello" ]
2015-02-20 03:27:20 +03:00
ENV abc = def
ENV ghi = $ abc
RUN [ "$ghi" = "def" ]
2014-08-13 14:07:41 +04:00
`
2014-07-06 15:36:34 +04:00
ctx , err := fakeContext ( dockerfile , map [ string ] string {
"hello/docker/world" : "hello" ,
} )
if err != nil {
t . Fatal ( err )
}
2014-11-20 20:38:41 +03:00
defer ctx . Close ( )
2014-07-06 15:36:34 +04:00
_ , err = buildImageFromContext ( name , ctx , true )
if err != nil {
t . Fatal ( err )
}
logDone ( "build - environment variables usage" )
}
2014-09-26 06:28:24 +04:00
func TestBuildEnvUsage2 ( t * testing . T ) {
name := "testbuildenvusage2"
defer deleteImages ( name )
dockerfile := ` FROM busybox
ENV abc = def
RUN [ "$abc" = "def" ]
ENV def = "hello world"
RUN [ "$def" = "hello world" ]
ENV def = hello \ world
RUN [ "$def" = "hello world" ]
ENV v1 = abc v2 = "hi there"
RUN [ "$v1" = "abc" ]
RUN [ "$v2" = "hi there" ]
ENV v3 = ' boogie nights ' v4 = "with'quotes too"
RUN [ "$v3" = "boogie nights" ]
RUN [ "$v4" = "with'quotes too" ]
ENV abc = zzz FROM = hello / docker / world
ENV abc = zzz TO = / docker / world / hello
ADD $ FROM $ TO
RUN [ "$(cat $TO)" = "hello" ]
ENV abc "zzz"
RUN [ $ abc = \ "zzz\" ]
ENV abc ' yyy '
RUN [ $ abc = \ ' yyy \ ' ]
ENV abc =
RUN [ "$abc" = "" ]
2015-02-20 03:27:20 +03:00
# use grep to make sure if the builder substitutes \ $ foo by mistake
# we don ' t get a false positive
ENV abc = \ $ foo
RUN [ "$abc" = "\$foo" ] && ( echo "$abc" | grep foo )
ENV abc \ $ foo
RUN [ "$abc" = "\$foo" ] && ( echo "$abc" | grep foo )
ENV abc = \ ' foo \ '
RUN [ "$abc" = "'foo'" ]
ENV abc = \ "foo\"
RUN [ "$abc" = "\"foo\"" ]
ENV abc "foo"
RUN [ "$abc" = "\"foo\"" ]
ENV abc ' foo '
RUN [ "$abc" = "'foo'" ]
ENV abc \ ' foo \ '
RUN [ "$abc" = "\\'foo\\'" ]
ENV abc \ "foo\"
RUN [ "$abc" = "\\\"foo\\\"" ]
2014-09-26 06:28:24 +04:00
`
ctx , err := fakeContext ( dockerfile , map [ string ] string {
"hello/docker/world" : "hello" ,
} )
if err != nil {
t . Fatal ( err )
}
2015-02-25 11:53:43 +03:00
defer ctx . Close ( )
2014-09-26 06:28:24 +04:00
_ , err = buildImageFromContext ( name , ctx , true )
if err != nil {
t . Fatal ( err )
}
logDone ( "build - environment variables usage2" )
}
2014-07-06 15:36:34 +04:00
func TestBuildAddScript ( t * testing . T ) {
name := "testbuildaddscript"
defer deleteImages ( name )
dockerfile := `
FROM busybox
ADD test / test
RUN [ "chmod" , "+x" , "/test" ]
RUN [ "/test" ]
RUN [ "$(cat /testfile)" = ' test ! ' ] `
ctx , err := fakeContext ( dockerfile , map [ string ] string {
"test" : "#!/bin/sh\necho 'test!' > /testfile" ,
} )
if err != nil {
t . Fatal ( err )
}
2014-11-20 20:38:41 +03:00
defer ctx . Close ( )
2014-07-06 15:36:34 +04:00
_ , err = buildImageFromContext ( name , ctx , true )
if err != nil {
t . Fatal ( err )
}
logDone ( "build - add and run script" )
}
2014-07-08 23:34:04 +04:00
func TestBuildAddTar ( t * testing . T ) {
2014-07-09 13:39:38 +04:00
name := "testbuildaddtar"
defer deleteImages ( name )
2014-07-08 23:34:04 +04:00
2014-07-21 23:10:47 +04:00
ctx := func ( ) * FakeContext {
2014-07-22 02:02:31 +04:00
dockerfile := `
FROM busybox
ADD test . tar /
RUN cat / test / foo | grep Hi
ADD test . tar / test . tar
RUN cat / test . tar / test / foo | grep Hi
ADD test . tar / unlikely - to - exist
RUN cat / unlikely - to - exist / test / foo | grep Hi
ADD test . tar / unlikely - to - exist - trailing - slash /
RUN cat / unlikely - to - exist - trailing - slash / test / foo | grep Hi
RUN mkdir / existing - directory
ADD test . tar / existing - directory
RUN cat / existing - directory / test / foo | grep Hi
ADD test . tar / existing - directory - trailing - slash /
RUN cat / existing - directory - trailing - slash / test / foo | grep Hi `
2014-07-21 23:10:47 +04:00
tmpDir , err := ioutil . TempDir ( "" , "fake-context" )
testTar , err := os . Create ( filepath . Join ( tmpDir , "test.tar" ) )
if err != nil {
t . Fatalf ( "failed to create test.tar archive: %v" , err )
2014-07-08 23:34:04 +04:00
}
2014-07-21 23:10:47 +04:00
defer testTar . Close ( )
tw := tar . NewWriter ( testTar )
if err := tw . WriteHeader ( & tar . Header {
Name : "test/foo" ,
Size : 2 ,
} ) ; err != nil {
t . Fatalf ( "failed to write tar file header: %v" , err )
}
if _ , err := tw . Write ( [ ] byte ( "Hi" ) ) ; err != nil {
t . Fatalf ( "failed to write tar file content: %v" , err )
}
if err := tw . Close ( ) ; err != nil {
t . Fatalf ( "failed to close tar archive: %v" , err )
2014-07-08 23:34:04 +04:00
}
2014-07-22 02:02:31 +04:00
if err := ioutil . WriteFile ( filepath . Join ( tmpDir , "Dockerfile" ) , [ ] byte ( dockerfile ) , 0644 ) ; err != nil {
2014-07-21 23:10:47 +04:00
t . Fatalf ( "failed to open destination dockerfile: %v" , err )
}
2015-03-10 06:53:28 +03:00
return fakeContextFromDir ( tmpDir )
2014-07-21 23:10:47 +04:00
} ( )
2014-11-20 20:38:41 +03:00
defer ctx . Close ( )
2014-07-21 23:10:47 +04:00
if _ , err := buildImageFromContext ( name , ctx , true ) ; err != nil {
t . Fatalf ( "build failed to complete for TestBuildAddTar: %v" , err )
2014-07-08 23:34:04 +04:00
}
2014-07-21 22:55:43 +04:00
2014-07-09 13:39:38 +04:00
logDone ( "build - ADD tar" )
2014-07-08 23:34:04 +04:00
}
2014-07-24 11:19:16 +04:00
2014-12-08 23:40:27 +03:00
func TestBuildAddTarXz ( t * testing . T ) {
name := "testbuildaddtarxz"
defer deleteImages ( name )
ctx := func ( ) * FakeContext {
dockerfile := `
FROM busybox
ADD test . tar . xz /
RUN cat / test / foo | grep Hi `
tmpDir , err := ioutil . TempDir ( "" , "fake-context" )
testTar , err := os . Create ( filepath . Join ( tmpDir , "test.tar" ) )
if err != nil {
t . Fatalf ( "failed to create test.tar archive: %v" , err )
}
defer testTar . Close ( )
tw := tar . NewWriter ( testTar )
if err := tw . WriteHeader ( & tar . Header {
Name : "test/foo" ,
Size : 2 ,
} ) ; err != nil {
t . Fatalf ( "failed to write tar file header: %v" , err )
}
if _ , err := tw . Write ( [ ] byte ( "Hi" ) ) ; err != nil {
t . Fatalf ( "failed to write tar file content: %v" , err )
}
if err := tw . Close ( ) ; err != nil {
t . Fatalf ( "failed to close tar archive: %v" , err )
}
2015-02-13 02:42:27 +03:00
xzCompressCmd := exec . Command ( "xz" , "-k" , "test.tar" )
2014-12-08 23:40:27 +03:00
xzCompressCmd . Dir = tmpDir
out , _ , err := runCommandWithOutput ( xzCompressCmd )
if err != nil {
t . Fatal ( err , out )
}
if err := ioutil . WriteFile ( filepath . Join ( tmpDir , "Dockerfile" ) , [ ] byte ( dockerfile ) , 0644 ) ; err != nil {
t . Fatalf ( "failed to open destination dockerfile: %v" , err )
}
2015-03-10 06:53:28 +03:00
return fakeContextFromDir ( tmpDir )
2014-12-08 23:40:27 +03:00
} ( )
defer ctx . Close ( )
if _ , err := buildImageFromContext ( name , ctx , true ) ; err != nil {
t . Fatalf ( "build failed to complete for TestBuildAddTarXz: %v" , err )
}
logDone ( "build - ADD tar.xz" )
}
func TestBuildAddTarXzGz ( t * testing . T ) {
name := "testbuildaddtarxzgz"
defer deleteImages ( name )
ctx := func ( ) * FakeContext {
dockerfile := `
FROM busybox
ADD test . tar . xz . gz /
RUN ls / test . tar . xz . gz `
tmpDir , err := ioutil . TempDir ( "" , "fake-context" )
testTar , err := os . Create ( filepath . Join ( tmpDir , "test.tar" ) )
if err != nil {
t . Fatalf ( "failed to create test.tar archive: %v" , err )
}
defer testTar . Close ( )
tw := tar . NewWriter ( testTar )
if err := tw . WriteHeader ( & tar . Header {
Name : "test/foo" ,
Size : 2 ,
} ) ; err != nil {
t . Fatalf ( "failed to write tar file header: %v" , err )
}
if _ , err := tw . Write ( [ ] byte ( "Hi" ) ) ; err != nil {
t . Fatalf ( "failed to write tar file content: %v" , err )
}
if err := tw . Close ( ) ; err != nil {
t . Fatalf ( "failed to close tar archive: %v" , err )
}
2015-02-13 02:42:27 +03:00
xzCompressCmd := exec . Command ( "xz" , "-k" , "test.tar" )
2014-12-08 23:40:27 +03:00
xzCompressCmd . Dir = tmpDir
out , _ , err := runCommandWithOutput ( xzCompressCmd )
if err != nil {
t . Fatal ( err , out )
}
gzipCompressCmd := exec . Command ( "gzip" , "test.tar.xz" )
gzipCompressCmd . Dir = tmpDir
out , _ , err = runCommandWithOutput ( gzipCompressCmd )
if err != nil {
t . Fatal ( err , out )
}
if err := ioutil . WriteFile ( filepath . Join ( tmpDir , "Dockerfile" ) , [ ] byte ( dockerfile ) , 0644 ) ; err != nil {
t . Fatalf ( "failed to open destination dockerfile: %v" , err )
}
2015-03-10 06:53:28 +03:00
return fakeContextFromDir ( tmpDir )
2014-12-08 23:40:27 +03:00
} ( )
defer ctx . Close ( )
if _ , err := buildImageFromContext ( name , ctx , true ) ; err != nil {
t . Fatalf ( "build failed to complete for TestBuildAddTarXz: %v" , err )
}
logDone ( "build - ADD tar.xz.gz" )
}
2014-07-24 11:19:16 +04:00
func TestBuildFromGIT ( t * testing . T ) {
name := "testbuildfromgit"
defer deleteImages ( name )
git , err := fakeGIT ( "repo" , map [ string ] string {
"Dockerfile" : ` FROM busybox
ADD first / first
RUN [ - f / first ]
MAINTAINER docker ` ,
"first" : "test git data" ,
2015-03-10 06:53:28 +03:00
} , true )
2014-07-24 11:19:16 +04:00
if err != nil {
t . Fatal ( err )
}
defer git . Close ( )
_ , err = buildImageFromPath ( name , git . RepoURL , true )
if err != nil {
t . Fatal ( err )
}
res , err := inspectField ( name , "Author" )
if err != nil {
t . Fatal ( err )
}
if res != "docker" {
2014-08-13 11:37:30 +04:00
t . Fatalf ( "Maintainer should be docker, got %s" , res )
2014-07-24 11:19:16 +04:00
}
logDone ( "build - build from GIT" )
}
2014-07-08 21:37:20 +04:00
func TestBuildCleanupCmdOnEntrypoint ( t * testing . T ) {
name := "testbuildcmdcleanuponentrypoint"
defer deleteImages ( name )
if _ , err := buildImage ( name ,
` FROM scratch
CMD [ "test" ]
ENTRYPOINT [ "echo" ] ` ,
true ) ; err != nil {
t . Fatal ( err )
}
if _ , err := buildImage ( name ,
fmt . Sprintf ( ` FROM % s
ENTRYPOINT [ "cat" ] ` , name ) ,
true ) ; err != nil {
t . Fatal ( err )
}
res , err := inspectField ( name , "Config.Cmd" )
if err != nil {
t . Fatal ( err )
}
if expected := "<no value>" ; res != expected {
t . Fatalf ( "Cmd %s, expected %s" , res , expected )
}
res , err = inspectField ( name , "Config.Entrypoint" )
if err != nil {
t . Fatal ( err )
}
if expected := "[cat]" ; res != expected {
t . Fatalf ( "Entrypoint %s, expected %s" , res , expected )
}
logDone ( "build - cleanup cmd on ENTRYPOINT" )
}
2014-08-30 15:34:09 +04:00
func TestBuildClearCmd ( t * testing . T ) {
name := "testbuildclearcmd"
defer deleteImages ( name )
_ , err := buildImage ( name ,
` From scratch
ENTRYPOINT [ "/bin/bash" ]
CMD [ ] ` ,
true )
if err != nil {
t . Fatal ( err )
}
res , err := inspectFieldJSON ( name , "Config.Cmd" )
if err != nil {
t . Fatal ( err )
}
if res != "[]" {
t . Fatalf ( "Cmd %s, expected %s" , res , "[]" )
}
logDone ( "build - clearcmd" )
}
2014-09-23 10:18:46 +04:00
func TestBuildEmptyCmd ( t * testing . T ) {
name := "testbuildemptycmd"
defer deleteImages ( name )
if _ , err := buildImage ( name , "FROM scratch\nMAINTAINER quux\n" , true ) ; err != nil {
t . Fatal ( err )
}
res , err := inspectFieldJSON ( name , "Config.Cmd" )
if err != nil {
t . Fatal ( err )
}
if res != "null" {
t . Fatalf ( "Cmd %s, expected %s" , res , "null" )
}
logDone ( "build - empty cmd" )
}
2014-09-24 00:31:42 +04:00
func TestBuildOnBuildOutput ( t * testing . T ) {
name := "testbuildonbuildparent"
defer deleteImages ( name )
if _ , err := buildImage ( name , "FROM busybox\nONBUILD RUN echo foo\n" , true ) ; err != nil {
t . Fatal ( err )
}
childname := "testbuildonbuildchild"
defer deleteImages ( childname )
_ , out , err := buildImageWithOut ( name , "FROM " + name + "\nMAINTAINER quux\n" , true )
if err != nil {
t . Fatal ( err )
}
2014-10-14 00:14:35 +04:00
if ! strings . Contains ( out , "Trigger 0, RUN echo foo" ) {
t . Fatal ( "failed to find the ONBUILD output" , out )
2014-09-24 00:31:42 +04:00
}
logDone ( "build - onbuild output" )
}
2014-09-29 13:52:13 +04:00
func TestBuildInvalidTag ( t * testing . T ) {
2014-10-08 06:07:51 +04:00
name := "abcd:" + makeRandomString ( 200 )
2014-09-29 13:52:13 +04:00
defer deleteImages ( name )
_ , out , err := buildImageWithOut ( name , "FROM scratch\nMAINTAINER quux\n" , true )
// if the error doesnt check for illegal tag name, or the image is built
// then this should fail
2014-10-08 06:07:51 +04:00
if ! strings . Contains ( out , "Illegal tag name" ) || strings . Contains ( out , "Sending build context to Docker daemon" ) {
2014-09-29 13:52:13 +04:00
t . Fatalf ( "failed to stop before building. Error: %s, Output: %s" , err , out )
}
logDone ( "build - invalid tag" )
}
2014-09-29 21:23:10 +04:00
func TestBuildCmdShDashC ( t * testing . T ) {
name := "testbuildcmdshc"
defer deleteImages ( name )
if _ , err := buildImage ( name , "FROM busybox\nCMD echo cmd\n" , true ) ; err != nil {
t . Fatal ( err )
}
res , err := inspectFieldJSON ( name , "Config.Cmd" )
if err != nil {
t . Fatal ( err , res )
}
expected := ` ["/bin/sh","-c","echo cmd"] `
if res != expected {
t . Fatalf ( "Expected value %s not in Config.Cmd: %s" , expected , res )
}
logDone ( "build - cmd should have sh -c for non-json" )
}
2015-01-15 22:34:59 +03:00
func TestBuildCmdSpaces ( t * testing . T ) {
// Test to make sure that when we strcat arrays we take into account
// the arg separator to make sure ["echo","hi"] and ["echo hi"] don't
// look the same
name := "testbuildcmdspaces"
defer deleteImages ( name )
var id1 string
var id2 string
var err error
if id1 , err = buildImage ( name , "FROM busybox\nCMD [\"echo hi\"]\n" , true ) ; err != nil {
t . Fatal ( err )
}
if id2 , err = buildImage ( name , "FROM busybox\nCMD [\"echo\", \"hi\"]\n" , true ) ; err != nil {
t . Fatal ( err )
}
if id1 == id2 {
t . Fatal ( "Should not have resulted in the same CMD" )
}
// Now do the same with ENTRYPOINT
if id1 , err = buildImage ( name , "FROM busybox\nENTRYPOINT [\"echo hi\"]\n" , true ) ; err != nil {
t . Fatal ( err )
}
if id2 , err = buildImage ( name , "FROM busybox\nENTRYPOINT [\"echo\", \"hi\"]\n" , true ) ; err != nil {
t . Fatal ( err )
}
if id1 == id2 {
t . Fatal ( "Should not have resulted in the same ENTRYPOINT" )
}
logDone ( "build - cmd with spaces" )
}
2014-09-29 21:23:10 +04:00
func TestBuildCmdJSONNoShDashC ( t * testing . T ) {
name := "testbuildcmdjson"
defer deleteImages ( name )
if _ , err := buildImage ( name , "FROM busybox\nCMD [\"echo\", \"cmd\"]" , true ) ; err != nil {
t . Fatal ( err )
}
res , err := inspectFieldJSON ( name , "Config.Cmd" )
if err != nil {
t . Fatal ( err , res )
}
expected := ` ["echo","cmd"] `
if res != expected {
t . Fatalf ( "Expected value %s not in Config.Cmd: %s" , expected , res )
}
logDone ( "build - cmd should not have /bin/sh -c for json" )
}
2014-10-07 07:14:25 +04:00
2015-02-05 18:23:25 +03:00
func TestBuildErrorInvalidInstruction ( t * testing . T ) {
2014-10-07 07:14:25 +04:00
name := "testbuildignoreinvalidinstruction"
defer deleteImages ( name )
out , _ , err := buildImageWithOut ( name , "FROM busybox\nfoo bar" , true )
2015-02-05 18:23:25 +03:00
if err == nil {
t . Fatalf ( "Should have failed: %s" , out )
2014-10-07 07:14:25 +04:00
}
2015-02-05 18:23:25 +03:00
logDone ( "build - error invalid Dockerfile instruction" )
2014-10-07 07:14:25 +04:00
}
2014-10-08 02:39:50 +04:00
func TestBuildEntrypointInheritance ( t * testing . T ) {
defer deleteImages ( "parent" , "child" )
2014-11-17 19:05:49 +03:00
defer deleteAllContainers ( )
2014-10-08 02:39:50 +04:00
if _ , err := buildImage ( "parent" , `
FROM busybox
ENTRYPOINT exit 130
` , true ) ; err != nil {
t . Fatal ( err )
}
status , _ := runCommand ( exec . Command ( dockerBinary , "run" , "parent" ) )
if status != 130 {
t . Fatalf ( "expected exit code 130 but received %d" , status )
}
if _ , err := buildImage ( "child" , `
FROM parent
ENTRYPOINT exit 5
` , true ) ; err != nil {
t . Fatal ( err )
}
status , _ = runCommand ( exec . Command ( dockerBinary , "run" , "child" ) )
if status != 5 {
2014-11-05 19:26:22 +03:00
t . Fatalf ( "expected exit code 5 but received %d" , status )
2014-10-08 02:39:50 +04:00
}
logDone ( "build - clear entrypoint" )
}
func TestBuildEntrypointInheritanceInspect ( t * testing . T ) {
var (
name = "testbuildepinherit"
name2 = "testbuildepinherit2"
expected = ` ["/bin/sh","-c","echo quux"] `
)
defer deleteImages ( name , name2 )
2014-11-17 19:05:49 +03:00
defer deleteAllContainers ( )
2014-10-08 02:39:50 +04:00
if _ , err := buildImage ( name , "FROM busybox\nENTRYPOINT /foo/bar" , true ) ; err != nil {
t . Fatal ( err )
}
if _ , err := buildImage ( name2 , fmt . Sprintf ( "FROM %s\nENTRYPOINT echo quux" , name ) , true ) ; err != nil {
t . Fatal ( err )
}
res , err := inspectFieldJSON ( name2 , "Config.Entrypoint" )
if err != nil {
t . Fatal ( err , res )
}
if res != expected {
t . Fatalf ( "Expected value %s not in Config.Entrypoint: %s" , expected , res )
}
out , _ , err := runCommandWithOutput ( exec . Command ( dockerBinary , "run" , "-t" , name2 ) )
if err != nil {
t . Fatal ( err , out )
}
expected = "quux"
if strings . TrimSpace ( out ) != expected {
t . Fatalf ( "Expected output is %s, got %s" , expected , out )
}
logDone ( "build - entrypoint override inheritance properly" )
}
func TestBuildRunShEntrypoint ( t * testing . T ) {
name := "testbuildentrypoint"
defer deleteImages ( name )
_ , err := buildImage ( name ,
` FROM busybox
ENTRYPOINT / bin / echo ` ,
true )
if err != nil {
t . Fatal ( err )
}
2014-11-17 19:05:49 +03:00
out , _ , err := runCommandWithOutput ( exec . Command ( dockerBinary , "run" , "--rm" , name ) )
2014-10-08 02:39:50 +04:00
if err != nil {
t . Fatal ( err , out )
}
logDone ( "build - entrypoint with /bin/echo running successfully" )
}
2014-10-14 10:58:55 +04:00
func TestBuildExoticShellInterpolation ( t * testing . T ) {
name := "testbuildexoticshellinterpolation"
defer deleteImages ( name )
_ , err := buildImage ( name , `
FROM busybox
2015-02-06 17:33:01 +03:00
2014-10-14 10:58:55 +04:00
ENV SOME_VAR a . b . c
RUN [ "$SOME_VAR" = ' a . b . c ' ]
RUN [ "${SOME_VAR}" = ' a . b . c ' ]
RUN [ "${SOME_VAR%.*}" = ' a . b ' ]
RUN [ "${SOME_VAR%%.*}" = 'a' ]
RUN [ "${SOME_VAR#*.}" = ' b . c ' ]
RUN [ "${SOME_VAR##*.}" = 'c' ]
RUN [ "${SOME_VAR/c/d}" = ' a . b . d ' ]
RUN [ "${#SOME_VAR}" = '5' ]
RUN [ "${SOME_UNSET_VAR:-$SOME_VAR}" = ' a . b . c ' ]
RUN [ "${SOME_VAR:+Version: ${SOME_VAR}}" = ' Version : a . b . c ' ]
RUN [ "${SOME_UNSET_VAR:+${SOME_VAR}}" = ' ' ]
RUN [ "${SOME_UNSET_VAR:-${SOME_VAR:-d.e.f}}" = ' a . b . c ' ]
` , false )
if err != nil {
t . Fatal ( err )
}
logDone ( "build - exotic shell interpolation" )
}
2014-10-09 07:34:20 +04:00
func TestBuildVerifySingleQuoteFails ( t * testing . T ) {
// This testcase is supposed to generate an error because the
// JSON array we're passing in on the CMD uses single quotes instead
// of double quotes (per the JSON spec). This means we interpret it
// as a "string" insead of "JSON array" and pass it on to "sh -c" and
// it should barf on it.
name := "testbuildsinglequotefails"
defer deleteImages ( name )
2014-11-17 19:05:49 +03:00
defer deleteAllContainers ( )
2014-10-09 07:34:20 +04:00
_ , err := buildImage ( name ,
` FROM busybox
CMD [ ' / bin / sh ' , ' - c ' , ' echo hi ' ] ` ,
true )
2014-11-17 19:05:49 +03:00
_ , _ , err = runCommandWithOutput ( exec . Command ( dockerBinary , "run" , "--rm" , name ) )
2014-10-09 07:34:20 +04:00
if err == nil {
t . Fatal ( "The image was not supposed to be able to run" )
}
2015-02-10 02:01:52 +03:00
logDone ( "build - verify single quotes break the build" )
2014-10-09 07:34:20 +04:00
}
2014-10-06 20:41:22 +04:00
func TestBuildVerboseOut ( t * testing . T ) {
name := "testbuildverboseout"
defer deleteImages ( name )
_ , out , err := buildImageWithOut ( name ,
` FROM busybox
RUN echo 123 ` ,
false )
if err != nil {
t . Fatal ( err )
}
if ! strings . Contains ( out , "\n123\n" ) {
t . Fatalf ( "Output should contain %q: %q" , "123" , out )
}
logDone ( "build - verbose output from commands" )
}
2014-10-09 01:55:02 +04:00
func TestBuildWithTabs ( t * testing . T ) {
name := "testbuildwithtabs"
defer deleteImages ( name )
_ , err := buildImage ( name ,
"FROM busybox\nRUN echo\tone\t\ttwo" , true )
if err != nil {
t . Fatal ( err )
}
res , err := inspectFieldJSON ( name , "ContainerConfig.Cmd" )
if err != nil {
t . Fatal ( err )
}
2015-01-20 22:11:59 +03:00
expected1 := ` ["/bin/sh","-c","echo\tone\t\ttwo"] `
expected2 := ` ["/bin/sh","-c","echo\u0009one\u0009\u0009two"] ` // syntactically equivalent, and what Go 1.3 generates
if res != expected1 && res != expected2 {
t . Fatalf ( "Missing tabs.\nGot: %s\nExp: %s or %s" , res , expected1 , expected2 )
2014-10-09 01:55:02 +04:00
}
logDone ( "build - with tabs" )
}
2014-12-05 01:06:40 +03:00
2015-02-17 18:20:06 +03:00
func TestBuildLabels ( t * testing . T ) {
name := "testbuildlabel"
expected := ` { "License":"GPL","Vendor":"Acme"} `
defer deleteImages ( name )
_ , err := buildImage ( name ,
` FROM busybox
LABEL Vendor = Acme
LABEL License GPL ` ,
true )
if err != nil {
t . Fatal ( err )
}
res , err := inspectFieldJSON ( name , "Config.Labels" )
if err != nil {
t . Fatal ( err )
}
if res != expected {
t . Fatalf ( "Labels %s, expected %s" , res , expected )
}
logDone ( "build - label" )
}
2015-03-19 20:06:06 +03:00
func TestBuildLabelsCache ( t * testing . T ) {
name := "testbuildlabelcache"
defer deleteImages ( name )
id1 , err := buildImage ( name ,
` FROM busybox
LABEL Vendor = Acme ` , false )
if err != nil {
t . Fatalf ( "Build 1 should have worked: %v" , err )
}
id2 , err := buildImage ( name ,
` FROM busybox
LABEL Vendor = Acme ` , true )
if err != nil || id1 != id2 {
t . Fatalf ( "Build 2 should have worked & used cache(%s,%s): %v" , id1 , id2 , err )
}
id2 , err = buildImage ( name ,
` FROM busybox
LABEL Vendor = Acme1 ` , true )
if err != nil || id1 == id2 {
2015-03-20 15:14:31 +03:00
t . Fatalf ( "Build 3 should have worked & NOT used cache(%s,%s): %v" , id1 , id2 , err )
2015-03-19 20:06:06 +03:00
}
id2 , err = buildImage ( name ,
` FROM busybox
LABEL Vendor Acme ` , true ) // Note: " " and "=" should be same
if err != nil || id1 != id2 {
2015-03-20 15:14:31 +03:00
t . Fatalf ( "Build 4 should have worked & used cache(%s,%s): %v" , id1 , id2 , err )
}
// Now make sure the cache isn't used by mistake
id1 , err = buildImage ( name ,
` FROM busybox
LABEL f1 = b1 f2 = b2 ` , false )
if err != nil {
t . Fatalf ( "Build 5 should have worked: %q" , err )
}
id2 , err = buildImage ( name ,
` FROM busybox
LABEL f1 = "b1 f2=b2" ` , true )
if err != nil || id1 == id2 {
t . Fatalf ( "Build 6 should have worked & NOT used the cache(%s,%s): %q" , id1 , id2 , err )
2015-03-19 20:06:06 +03:00
}
logDone ( "build - label cache" )
}
2014-12-05 01:06:40 +03:00
func TestBuildStderr ( t * testing . T ) {
// This test just makes sure that no non-error output goes
// to stderr
name := "testbuildstderr"
defer deleteImages ( name )
_ , _ , stderr , err := buildImageWithStdoutStderr ( name ,
"FROM busybox\nRUN echo one" , true )
if err != nil {
t . Fatal ( err )
}
2015-03-16 09:59:10 +03:00
if runtime . GOOS == "windows" {
// stderr might contain a security warning on windows
lines := strings . Split ( stderr , "\n" )
for _ , v := range lines {
if v != "" && ! strings . Contains ( v , "SECURITY WARNING:" ) {
t . Fatalf ( "Stderr contains unexpected output line: %q" , v )
}
}
} else {
if stderr != "" {
t . Fatalf ( "Stderr should have been empty, instead its: %q" , stderr )
}
2014-12-05 01:06:40 +03:00
}
logDone ( "build - testing stderr" )
}
2014-12-10 22:09:03 +03:00
func TestBuildChownSingleFile ( t * testing . T ) {
2015-02-20 12:37:27 +03:00
testRequires ( t , UnixCli ) // test uses chown: not available on windows
2014-12-10 22:09:03 +03:00
name := "testbuildchownsinglefile"
defer deleteImages ( name )
ctx , err := fakeContext ( `
FROM busybox
COPY test /
RUN ls - l / test
RUN [ $ ( ls - l / test | awk ' { print $ 3 ":" $ 4 } ' ) = ' root : root ' ]
` , map [ string ] string {
"test" : "test" ,
} )
if err != nil {
t . Fatal ( err )
}
defer ctx . Close ( )
if err := os . Chown ( filepath . Join ( ctx . Dir , "test" ) , 4242 , 4242 ) ; err != nil {
t . Fatal ( err )
}
if _ , err := buildImageFromContext ( name , ctx , true ) ; err != nil {
t . Fatal ( err )
}
logDone ( "build - change permission on single file" )
}
2014-12-03 22:04:51 +03:00
func TestBuildSymlinkBreakout ( t * testing . T ) {
name := "testbuildsymlinkbreakout"
tmpdir , err := ioutil . TempDir ( "" , name )
if err != nil {
t . Fatal ( err )
}
defer os . RemoveAll ( tmpdir )
ctx := filepath . Join ( tmpdir , "context" )
if err := os . MkdirAll ( ctx , 0755 ) ; err != nil {
t . Fatal ( err )
}
if err := ioutil . WriteFile ( filepath . Join ( ctx , "Dockerfile" ) , [ ] byte ( `
from busybox
add symlink . tar /
add inject / symlink /
` ) , 0644 ) ; err != nil {
t . Fatal ( err )
}
inject := filepath . Join ( ctx , "inject" )
if err := ioutil . WriteFile ( inject , nil , 0644 ) ; err != nil {
t . Fatal ( err )
}
f , err := os . Create ( filepath . Join ( ctx , "symlink.tar" ) )
if err != nil {
t . Fatal ( err )
}
w := tar . NewWriter ( f )
w . WriteHeader ( & tar . Header {
Name : "symlink2" ,
Typeflag : tar . TypeSymlink ,
Linkname : "/../../../../../../../../../../../../../../" ,
Uid : os . Getuid ( ) ,
Gid : os . Getgid ( ) ,
} )
w . WriteHeader ( & tar . Header {
Name : "symlink" ,
Typeflag : tar . TypeSymlink ,
Linkname : filepath . Join ( "symlink2" , tmpdir ) ,
Uid : os . Getuid ( ) ,
Gid : os . Getgid ( ) ,
} )
w . Close ( )
f . Close ( )
2015-03-10 06:53:28 +03:00
if _ , err := buildImageFromContext ( name , fakeContextFromDir ( ctx ) , false ) ; err != nil {
2014-12-03 22:04:51 +03:00
t . Fatal ( err )
}
if _ , err := os . Lstat ( filepath . Join ( tmpdir , "inject" ) ) ; err == nil {
t . Fatal ( "symlink breakout - inject" )
} else if ! os . IsNotExist ( err ) {
t . Fatalf ( "unexpected error: %v" , err )
}
logDone ( "build - symlink breakout" )
}
2014-12-09 01:33:46 +03:00
func TestBuildXZHost ( t * testing . T ) {
name := "testbuildxzhost"
defer deleteImages ( name )
ctx , err := fakeContext ( `
FROM busybox
ADD xz / usr / local / sbin /
RUN chmod 755 / usr / local / sbin / xz
ADD test . xz /
RUN [ ! - e / injected ] ` ,
map [ string ] string {
"test.xz" : "\xfd\x37\x7a\x58\x5a\x00\x00\x04\xe6\xd6\xb4\x46\x02\x00" +
"\x21\x01\x16\x00\x00\x00\x74\x2f\xe5\xa3\x01\x00\x3f\xfd" +
"\x37\x7a\x58\x5a\x00\x00\x04\xe6\xd6\xb4\x46\x02\x00\x21" ,
"xz" : "#!/bin/sh\ntouch /injected" ,
} )
if err != nil {
t . Fatal ( err )
}
defer ctx . Close ( )
if _ , err := buildImageFromContext ( name , ctx , true ) ; err != nil {
t . Fatal ( err )
}
logDone ( "build - xz host is being used" )
}
2014-12-12 22:15:31 +03:00
func TestBuildVolumesRetainContents ( t * testing . T ) {
var (
name = "testbuildvolumescontent"
expected = "some text"
)
defer deleteImages ( name )
ctx , err := fakeContext ( `
FROM busybox
COPY content / foo / file
VOLUME / foo
CMD cat / foo / file ` ,
map [ string ] string {
"content" : expected ,
} )
if err != nil {
t . Fatal ( err )
}
defer ctx . Close ( )
if _ , err := buildImageFromContext ( name , ctx , false ) ; err != nil {
t . Fatal ( err )
}
out , _ , err := runCommandWithOutput ( exec . Command ( dockerBinary , "run" , "--rm" , name ) )
if err != nil {
t . Fatal ( err )
}
if out != expected {
t . Fatalf ( "expected file contents for /foo/file to be %q but received %q" , expected , out )
}
logDone ( "build - volumes retain contents in build" )
}
2014-09-11 18:42:17 +04:00
func TestBuildRenamedDockerfile ( t * testing . T ) {
defer deleteAllContainers ( )
ctx , err := fakeContext ( ` FROM busybox
RUN echo from Dockerfile ` ,
map [ string ] string {
"Dockerfile" : "FROM busybox\nRUN echo from Dockerfile" ,
"files/Dockerfile" : "FROM busybox\nRUN echo from files/Dockerfile" ,
"files/dFile" : "FROM busybox\nRUN echo from files/dFile" ,
"dFile" : "FROM busybox\nRUN echo from dFile" ,
2015-02-04 17:07:37 +03:00
"files/dFile2" : "FROM busybox\nRUN echo from files/dFile2" ,
2014-09-11 18:42:17 +04:00
} )
defer ctx . Close ( )
if err != nil {
t . Fatal ( err )
}
out , _ , err := dockerCmdInDir ( t , ctx . Dir , "build" , "-t" , "test1" , "." )
if err != nil {
t . Fatalf ( "Failed to build: %s\n%s" , out , err )
}
if ! strings . Contains ( out , "from Dockerfile" ) {
2015-02-04 17:07:37 +03:00
t . Fatalf ( "test1 should have used Dockerfile, output:%s" , out )
2014-09-11 18:42:17 +04:00
}
2015-02-18 10:59:13 +03:00
out , _ , err = dockerCmdInDir ( t , ctx . Dir , "build" , "-f" , filepath . Join ( "files" , "Dockerfile" ) , "-t" , "test2" , "." )
2014-09-11 18:42:17 +04:00
if err != nil {
t . Fatal ( err )
}
if ! strings . Contains ( out , "from files/Dockerfile" ) {
2015-02-04 17:07:37 +03:00
t . Fatalf ( "test2 should have used files/Dockerfile, output:%s" , out )
2014-09-11 18:42:17 +04:00
}
2015-02-18 10:59:13 +03:00
out , _ , err = dockerCmdInDir ( t , ctx . Dir , "build" , fmt . Sprintf ( "--file=%s" , filepath . Join ( "files" , "dFile" ) ) , "-t" , "test3" , "." )
2014-09-11 18:42:17 +04:00
if err != nil {
t . Fatal ( err )
}
if ! strings . Contains ( out , "from files/dFile" ) {
2015-02-04 17:07:37 +03:00
t . Fatalf ( "test3 should have used files/dFile, output:%s" , out )
2014-09-11 18:42:17 +04:00
}
out , _ , err = dockerCmdInDir ( t , ctx . Dir , "build" , "--file=dFile" , "-t" , "test4" , "." )
if err != nil {
t . Fatal ( err )
}
if ! strings . Contains ( out , "from dFile" ) {
2015-02-04 17:07:37 +03:00
t . Fatalf ( "test4 should have used dFile, output:%s" , out )
2014-09-11 18:42:17 +04:00
}
2015-02-18 10:59:13 +03:00
dirWithNoDockerfile , _ := ioutil . TempDir ( os . TempDir ( ) , "test5" )
nonDockerfileFile := filepath . Join ( dirWithNoDockerfile , "notDockerfile" )
if _ , err = os . Create ( nonDockerfileFile ) ; err != nil {
t . Fatal ( err )
}
out , _ , err = dockerCmdInDir ( t , ctx . Dir , "build" , fmt . Sprintf ( "--file=%s" , nonDockerfileFile ) , "-t" , "test5" , "." )
2014-09-11 18:42:17 +04:00
if err == nil {
2015-02-04 17:07:37 +03:00
t . Fatalf ( "test5 was supposed to fail to find passwd" )
2014-09-11 18:42:17 +04:00
}
2015-02-18 10:59:13 +03:00
if expected := fmt . Sprintf ( "The Dockerfile (%s) must be within the build context (.)" , strings . Replace ( nonDockerfileFile , ` \ ` , ` \\ ` , - 1 ) ) ; ! strings . Contains ( out , expected ) {
t . Fatalf ( "wrong error messsage:%v\nexpected to contain=%v" , out , expected )
2014-09-11 18:42:17 +04:00
}
2015-02-18 10:59:13 +03:00
out , _ , err = dockerCmdInDir ( t , filepath . Join ( ctx . Dir , "files" ) , "build" , "-f" , filepath . Join ( ".." , "Dockerfile" ) , "-t" , "test6" , ".." )
2014-09-11 18:42:17 +04:00
if err != nil {
2015-02-04 17:07:37 +03:00
t . Fatalf ( "test6 failed: %s" , err )
2014-09-11 18:42:17 +04:00
}
if ! strings . Contains ( out , "from Dockerfile" ) {
2015-02-04 17:07:37 +03:00
t . Fatalf ( "test6 should have used root Dockerfile, output:%s" , out )
2014-09-11 18:42:17 +04:00
}
2015-02-18 10:59:13 +03:00
out , _ , err = dockerCmdInDir ( t , filepath . Join ( ctx . Dir , "files" ) , "build" , "-f" , filepath . Join ( ctx . Dir , "files" , "Dockerfile" ) , "-t" , "test7" , ".." )
2014-09-11 18:42:17 +04:00
if err != nil {
2015-02-04 17:07:37 +03:00
t . Fatalf ( "test7 failed: %s" , err )
2014-09-11 18:42:17 +04:00
}
if ! strings . Contains ( out , "from files/Dockerfile" ) {
2015-02-04 17:07:37 +03:00
t . Fatalf ( "test7 should have used files Dockerfile, output:%s" , out )
2014-09-11 18:42:17 +04:00
}
2015-02-18 10:59:13 +03:00
out , _ , err = dockerCmdInDir ( t , filepath . Join ( ctx . Dir , "files" ) , "build" , "-f" , filepath . Join ( ".." , "Dockerfile" ) , "-t" , "test8" , "." )
2014-09-11 18:42:17 +04:00
if err == nil || ! strings . Contains ( out , "must be within the build context" ) {
2015-02-04 17:07:37 +03:00
t . Fatalf ( "test8 should have failed with Dockerfile out of context: %s" , err )
2014-09-11 18:42:17 +04:00
}
2015-02-04 17:07:37 +03:00
tmpDir := os . TempDir ( )
out , _ , err = dockerCmdInDir ( t , tmpDir , "build" , "-t" , "test9" , ctx . Dir )
2014-09-11 18:42:17 +04:00
if err != nil {
2015-02-04 17:07:37 +03:00
t . Fatalf ( "test9 - failed: %s" , err )
2014-09-11 18:42:17 +04:00
}
if ! strings . Contains ( out , "from Dockerfile" ) {
2015-02-04 17:07:37 +03:00
t . Fatalf ( "test9 should have used root Dockerfile, output:%s" , out )
}
out , _ , err = dockerCmdInDir ( t , filepath . Join ( ctx . Dir , "files" ) , "build" , "-f" , "dFile2" , "-t" , "test10" , "." )
if err != nil {
t . Fatalf ( "test10 should have worked: %s" , err )
}
if ! strings . Contains ( out , "from files/dFile2" ) {
t . Fatalf ( "test10 should have used files/dFile2, output:%s" , out )
2014-09-11 18:42:17 +04:00
}
logDone ( "build - rename dockerfile" )
}
2014-10-07 05:54:52 +04:00
2015-02-17 21:25:36 +03:00
func TestBuildFromMixedcaseDockerfile ( t * testing . T ) {
2015-03-06 01:42:52 +03:00
testRequires ( t , UnixCli ) // Dockerfile overwrites dockerfile on windows
2015-02-17 21:25:36 +03:00
defer deleteImages ( "test1" )
ctx , err := fakeContext ( ` FROM busybox
RUN echo from dockerfile ` ,
map [ string ] string {
"dockerfile" : "FROM busybox\nRUN echo from dockerfile" ,
} )
defer ctx . Close ( )
if err != nil {
t . Fatal ( err )
}
out , _ , err := dockerCmdInDir ( t , ctx . Dir , "build" , "-t" , "test1" , "." )
if err != nil {
t . Fatalf ( "Failed to build: %s\n%s" , out , err )
}
if ! strings . Contains ( out , "from dockerfile" ) {
t . Fatalf ( "Missing proper output: %s" , out )
}
logDone ( "build - mixedcase Dockerfile" )
}
func TestBuildWithTwoDockerfiles ( t * testing . T ) {
2015-03-06 01:42:52 +03:00
testRequires ( t , UnixCli ) // Dockerfile overwrites dockerfile on windows
2015-02-17 21:25:36 +03:00
defer deleteImages ( "test1" )
ctx , err := fakeContext ( ` FROM busybox
RUN echo from Dockerfile ` ,
map [ string ] string {
"dockerfile" : "FROM busybox\nRUN echo from dockerfile" ,
} )
defer ctx . Close ( )
if err != nil {
t . Fatal ( err )
}
out , _ , err := dockerCmdInDir ( t , ctx . Dir , "build" , "-t" , "test1" , "." )
if err != nil {
t . Fatalf ( "Failed to build: %s\n%s" , out , err )
}
if ! strings . Contains ( out , "from Dockerfile" ) {
t . Fatalf ( "Missing proper output: %s" , out )
}
logDone ( "build - two Dockerfiles" )
}
func TestBuildFromURLWithF ( t * testing . T ) {
defer deleteImages ( "test1" )
server , err := fakeStorage ( map [ string ] string { "baz" : ` FROM busybox
RUN echo from baz
COPY * / tmp /
RUN find / tmp / ` } )
if err != nil {
t . Fatal ( err )
}
defer server . Close ( )
ctx , err := fakeContext ( ` FROM busybox
RUN echo from Dockerfile ` ,
map [ string ] string { } )
defer ctx . Close ( )
if err != nil {
t . Fatal ( err )
}
// Make sure that -f is ignored and that we don't use the Dockerfile
// that's in the current dir
2015-02-19 13:01:27 +03:00
out , _ , err := dockerCmdInDir ( t , ctx . Dir , "build" , "-f" , "baz" , "-t" , "test1" , server . URL ( ) + "/baz" )
2015-02-17 21:25:36 +03:00
if err != nil {
t . Fatalf ( "Failed to build: %s\n%s" , out , err )
}
if ! strings . Contains ( out , "from baz" ) ||
strings . Contains ( out , "/tmp/baz" ) ||
! strings . Contains ( out , "/tmp/Dockerfile" ) {
t . Fatalf ( "Missing proper output: %s" , out )
}
logDone ( "build - from URL with -f" )
}
func TestBuildFromStdinWithF ( t * testing . T ) {
defer deleteImages ( "test1" )
ctx , err := fakeContext ( ` FROM busybox
RUN echo from Dockerfile ` ,
map [ string ] string { } )
defer ctx . Close ( )
if err != nil {
t . Fatal ( err )
}
// Make sure that -f is ignored and that we don't use the Dockerfile
// that's in the current dir
dockerCommand := exec . Command ( dockerBinary , "build" , "-f" , "baz" , "-t" , "test1" , "-" )
dockerCommand . Dir = ctx . Dir
dockerCommand . Stdin = strings . NewReader ( ` FROM busybox
RUN echo from baz
COPY * / tmp /
RUN find / tmp / ` )
out , status , err := runCommandWithOutput ( dockerCommand )
if err != nil || status != 0 {
t . Fatalf ( "Error building: %s" , err )
}
if ! strings . Contains ( out , "from baz" ) ||
strings . Contains ( out , "/tmp/baz" ) ||
! strings . Contains ( out , "/tmp/Dockerfile" ) {
t . Fatalf ( "Missing proper output: %s" , out )
}
logDone ( "build - from stdin with -f" )
}
2014-10-07 05:54:52 +04:00
func TestBuildFromOfficialNames ( t * testing . T ) {
name := "testbuildfromofficial"
fromNames := [ ] string {
"busybox" ,
"docker.io/busybox" ,
"index.docker.io/busybox" ,
"library/busybox" ,
"docker.io/library/busybox" ,
"index.docker.io/library/busybox" ,
}
for idx , fromName := range fromNames {
imgName := fmt . Sprintf ( "%s%d" , name , idx )
_ , err := buildImage ( imgName , "FROM " + fromName , true )
if err != nil {
t . Errorf ( "Build failed using FROM %s: %s" , fromName , err )
}
deleteImages ( imgName )
}
logDone ( "build - from official names" )
}
2015-02-03 00:17:12 +03:00
func TestBuildDockerfileOutsideContext ( t * testing . T ) {
2015-02-20 12:37:27 +03:00
testRequires ( t , UnixCli ) // uses os.Symlink: not implemented in windows at the time of writing (go-1.4.2)
2015-02-03 00:17:12 +03:00
name := "testbuilddockerfileoutsidecontext"
tmpdir , err := ioutil . TempDir ( "" , name )
if err != nil {
t . Fatal ( err )
}
defer os . RemoveAll ( tmpdir )
ctx := filepath . Join ( tmpdir , "context" )
if err := os . MkdirAll ( ctx , 0755 ) ; err != nil {
t . Fatal ( err )
}
2015-02-04 17:07:37 +03:00
if err := ioutil . WriteFile ( filepath . Join ( ctx , "Dockerfile" ) , [ ] byte ( "FROM scratch\nENV X Y" ) , 0644 ) ; err != nil {
2015-02-03 00:17:12 +03:00
t . Fatal ( err )
}
wd , err := os . Getwd ( )
if err != nil {
t . Fatal ( err )
}
defer os . Chdir ( wd )
if err := os . Chdir ( ctx ) ; err != nil {
t . Fatal ( err )
}
2015-02-04 17:07:37 +03:00
if err := ioutil . WriteFile ( filepath . Join ( tmpdir , "outsideDockerfile" ) , [ ] byte ( "FROM scratch\nENV x y" ) , 0644 ) ; err != nil {
2015-02-03 00:17:12 +03:00
t . Fatal ( err )
}
2015-02-17 03:59:41 +03:00
if err := os . Symlink ( filepath . Join ( ".." , "outsideDockerfile" ) , filepath . Join ( ctx , "dockerfile1" ) ) ; err != nil {
2015-02-03 00:17:12 +03:00
t . Fatal ( err )
}
if err := os . Symlink ( filepath . Join ( tmpdir , "outsideDockerfile" ) , filepath . Join ( ctx , "dockerfile2" ) ) ; err != nil {
t . Fatal ( err )
}
2015-02-17 03:59:41 +03:00
2015-02-03 00:17:12 +03:00
for _ , dockerfilePath := range [ ] string {
2015-02-17 03:59:41 +03:00
filepath . Join ( ".." , "outsideDockerfile" ) ,
2015-02-03 00:17:12 +03:00
filepath . Join ( ctx , "dockerfile1" ) ,
filepath . Join ( ctx , "dockerfile2" ) ,
} {
out , _ , err := runCommandWithOutput ( exec . Command ( dockerBinary , "build" , "-t" , name , "--no-cache" , "-f" , dockerfilePath , "." ) )
if err == nil {
t . Fatalf ( "Expected error with %s. Out: %s" , dockerfilePath , out )
}
2015-02-04 17:07:37 +03:00
if ! strings . Contains ( out , "must be within the build context" ) && ! strings . Contains ( out , "Cannot locate Dockerfile" ) {
t . Fatalf ( "Unexpected error with %s. Out: %s" , dockerfilePath , out )
}
2015-02-03 00:17:12 +03:00
deleteImages ( name )
}
os . Chdir ( tmpdir )
// Path to Dockerfile should be resolved relative to working directory, not relative to context.
// There is a Dockerfile in the context, but since there is no Dockerfile in the current directory, the following should fail
out , _ , err := runCommandWithOutput ( exec . Command ( dockerBinary , "build" , "-t" , name , "--no-cache" , "-f" , "Dockerfile" , ctx ) )
if err == nil {
t . Fatalf ( "Expected error. Out: %s" , out )
}
deleteImages ( name )
logDone ( "build - Dockerfile outside context" )
}
2015-01-15 17:49:48 +03:00
func TestBuildSpaces ( t * testing . T ) {
// Test to make sure that leading/trailing spaces on a command
// doesn't change the error msg we get
var (
err1 error
err2 error
)
name := "testspaces"
defer deleteImages ( name )
2015-02-08 06:30:44 +03:00
ctx , err := fakeContext ( "FROM busybox\nCOPY\n" ,
2015-01-15 17:49:48 +03:00
map [ string ] string {
2015-02-08 06:30:44 +03:00
"Dockerfile" : "FROM busybox\nCOPY\n" ,
2015-01-15 17:49:48 +03:00
} )
if err != nil {
t . Fatal ( err )
}
defer ctx . Close ( )
if _ , err1 = buildImageFromContext ( name , ctx , false ) ; err1 == nil {
t . Fatal ( "Build 1 was supposed to fail, but didn't" )
}
2015-02-08 06:30:44 +03:00
ctx . Add ( "Dockerfile" , "FROM busybox\nCOPY " )
2015-01-15 17:49:48 +03:00
if _ , err2 = buildImageFromContext ( name , ctx , false ) ; err2 == nil {
t . Fatal ( "Build 2 was supposed to fail, but didn't" )
}
// Skip over the times
2015-03-11 20:43:56 +03:00
e1 := err1 . Error ( ) [ strings . Index ( err1 . Error ( ) , ` level= ` ) : ]
e2 := err2 . Error ( ) [ strings . Index ( err1 . Error ( ) , ` level= ` ) : ]
2015-01-15 17:49:48 +03:00
// Ignore whitespace since that's what were verifying doesn't change stuff
if strings . Replace ( e1 , " " , "" , - 1 ) != strings . Replace ( e2 , " " , "" , - 1 ) {
t . Fatalf ( "Build 2's error wasn't the same as build 1's\n1:%s\n2:%s" , err1 , err2 )
}
2015-02-08 06:30:44 +03:00
ctx . Add ( "Dockerfile" , "FROM busybox\n COPY" )
2015-01-15 17:49:48 +03:00
if _ , err2 = buildImageFromContext ( name , ctx , false ) ; err2 == nil {
t . Fatal ( "Build 3 was supposed to fail, but didn't" )
}
// Skip over the times
2015-03-11 20:43:56 +03:00
e1 = err1 . Error ( ) [ strings . Index ( err1 . Error ( ) , ` level= ` ) : ]
e2 = err2 . Error ( ) [ strings . Index ( err1 . Error ( ) , ` level= ` ) : ]
2015-01-15 17:49:48 +03:00
// Ignore whitespace since that's what were verifying doesn't change stuff
if strings . Replace ( e1 , " " , "" , - 1 ) != strings . Replace ( e2 , " " , "" , - 1 ) {
t . Fatalf ( "Build 3's error wasn't the same as build 1's\n1:%s\n3:%s" , err1 , err2 )
}
2015-02-08 06:30:44 +03:00
ctx . Add ( "Dockerfile" , "FROM busybox\n COPY " )
2015-01-15 17:49:48 +03:00
if _ , err2 = buildImageFromContext ( name , ctx , false ) ; err2 == nil {
t . Fatal ( "Build 4 was supposed to fail, but didn't" )
}
// Skip over the times
2015-03-11 20:43:56 +03:00
e1 = err1 . Error ( ) [ strings . Index ( err1 . Error ( ) , ` level= ` ) : ]
e2 = err2 . Error ( ) [ strings . Index ( err1 . Error ( ) , ` level= ` ) : ]
2015-01-15 17:49:48 +03:00
// Ignore whitespace since that's what were verifying doesn't change stuff
if strings . Replace ( e1 , " " , "" , - 1 ) != strings . Replace ( e2 , " " , "" , - 1 ) {
t . Fatalf ( "Build 4's error wasn't the same as build 1's\n1:%s\n4:%s" , err1 , err2 )
}
logDone ( "build - test spaces" )
}
func TestBuildSpacesWithQuotes ( t * testing . T ) {
// Test to make sure that spaces in quotes aren't lost
name := "testspacesquotes"
defer deleteImages ( name )
dockerfile := ` FROM busybox
RUN echo " \
foo " `
_ , out , err := buildImageWithOut ( name , dockerfile , false )
if err != nil {
t . Fatal ( "Build failed:" , err )
}
expecting := "\n foo \n"
if ! strings . Contains ( out , expecting ) {
t . Fatalf ( "Bad output: %q expecting to contian %q" , out , expecting )
}
logDone ( "build - test spaces with quotes" )
}
2015-01-15 06:30:28 +03:00
// #4393
func TestBuildVolumeFileExistsinContainer ( t * testing . T ) {
buildCmd := exec . Command ( dockerBinary , "build" , "-t" , "docker-test-errcreatevolumewithfile" , "-" )
buildCmd . Stdin = strings . NewReader ( `
FROM busybox
RUN touch / foo
VOLUME / foo
` )
out , _ , err := runCommandWithOutput ( buildCmd )
if err == nil || ! strings . Contains ( out , "file exists" ) {
t . Fatalf ( "expected build to fail when file exists in container at requested volume path" )
}
logDone ( "build - errors when volume is specified where a file exists" )
}
2015-02-04 20:34:25 +03:00
func TestBuildMissingArgs ( t * testing . T ) {
2015-02-08 06:30:44 +03:00
// Test to make sure that all Dockerfile commands (except the ones listed
// in skipCmds) will generate an error if no args are provided.
// Note: INSERT is deprecated so we exclude it because of that.
skipCmds := map [ string ] struct { } {
"CMD" : { } ,
"RUN" : { } ,
"ENTRYPOINT" : { } ,
"INSERT" : { } ,
2015-02-04 20:34:25 +03:00
}
defer deleteAllContainers ( )
2015-02-20 13:38:55 +03:00
for cmd := range command . Commands {
2015-02-08 06:30:44 +03:00
cmd = strings . ToUpper ( cmd )
if _ , ok := skipCmds [ cmd ] ; ok {
continue
}
2015-02-12 08:18:48 +03:00
var dockerfile string
2015-02-04 20:34:25 +03:00
if cmd == "FROM" {
dockerfile = cmd
} else {
// Add FROM to make sure we don't complain about it missing
dockerfile = "FROM busybox\n" + cmd
}
ctx , err := fakeContext ( dockerfile , map [ string ] string { } )
if err != nil {
t . Fatal ( err )
}
defer ctx . Close ( )
var out string
if out , err = buildImageFromContext ( "args" , ctx , true ) ; err == nil {
2015-02-08 06:30:44 +03:00
t . Fatalf ( "%s was supposed to fail. Out:%s" , cmd , out )
2015-02-04 20:34:25 +03:00
}
if ! strings . Contains ( err . Error ( ) , cmd + " requires" ) {
t . Fatalf ( "%s returned the wrong type of error:%s" , cmd , err )
}
}
logDone ( "build - verify missing args" )
}
2015-02-10 22:10:10 +03:00
func TestBuildEmptyScratch ( t * testing . T ) {
defer deleteImages ( "sc" )
_ , out , err := buildImageWithOut ( "sc" , "FROM scratch" , true )
if err == nil {
t . Fatalf ( "Build was supposed to fail" )
}
if ! strings . Contains ( out , "No image was generated" ) {
t . Fatalf ( "Wrong error message: %v" , out )
}
logDone ( "build - empty scratch Dockerfile" )
}
2015-02-17 05:38:52 +03:00
func TestBuildDotDotFile ( t * testing . T ) {
defer deleteImages ( "sc" )
ctx , err := fakeContext ( "FROM busybox\n" ,
map [ string ] string {
"..gitme" : "" ,
} )
if err != nil {
t . Fatal ( err )
}
defer ctx . Close ( )
if _ , err = buildImageFromContext ( "sc" , ctx , false ) ; err != nil {
t . Fatalf ( "Build was supposed to work: %s" , err )
}
logDone ( "build - ..file" )
}
2015-02-21 00:26:11 +03:00
func TestBuildNotVerbose ( t * testing . T ) {
defer deleteAllContainers ( )
defer deleteImages ( "verbose" )
ctx , err := fakeContext ( "FROM busybox\nENV abc=hi\nRUN echo $abc there" , map [ string ] string { } )
if err != nil {
t . Fatal ( err )
}
defer ctx . Close ( )
// First do it w/verbose - baseline
buildCmd := exec . Command ( dockerBinary , "build" , "--no-cache" , "-t" , "verbose" , "." )
buildCmd . Dir = ctx . Dir
out , _ , err := runCommandWithOutput ( buildCmd )
if err != nil {
t . Fatalf ( "failed to build the image w/o -q: %s, %v" , out , err )
}
if ! strings . Contains ( out , "hi there" ) {
t . Fatalf ( "missing output:%s\n" , out )
}
// Now do it w/o verbose
buildCmd = exec . Command ( dockerBinary , "build" , "--no-cache" , "-q" , "-t" , "verbose" , "." )
buildCmd . Dir = ctx . Dir
out , _ , err = runCommandWithOutput ( buildCmd )
if err != nil {
t . Fatalf ( "failed to build the image w/ -q: %s, %v" , out , err )
}
if strings . Contains ( out , "hi there" ) {
t . Fatalf ( "Bad output, should not contain 'hi there':%s" , out )
}
logDone ( "build - not verbose" )
}
2015-03-10 00:44:14 +03:00
func TestBuildRUNoneJSON ( t * testing . T ) {
name := "testbuildrunonejson"
defer deleteAllContainers ( )
defer deleteImages ( name )
2015-03-16 22:22:00 +03:00
ctx , err := fakeContext ( ` FROM hello - world : frozen
2015-03-10 00:44:14 +03:00
RUN [ "/hello" ] ` , map [ string ] string { } )
if err != nil {
t . Fatal ( err )
}
defer ctx . Close ( )
buildCmd := exec . Command ( dockerBinary , "build" , "--no-cache" , "-t" , name , "." )
buildCmd . Dir = ctx . Dir
out , _ , err := runCommandWithOutput ( buildCmd )
if err != nil {
t . Fatalf ( "failed to build the image: %s, %v" , out , err )
}
if ! strings . Contains ( out , "Hello from Docker" ) {
t . Fatalf ( "bad output: %s" , out )
}
logDone ( "build - RUN with one JSON arg" )
}
2015-02-06 17:33:01 +03:00
func TestBuildResourceConstraintsAreUsed ( t * testing . T ) {
name := "testbuildresourceconstraints"
defer deleteAllContainers ( )
defer deleteImages ( name )
ctx , err := fakeContext ( `
FROM hello - world : frozen
RUN [ "/hello" ]
` , map [ string ] string { } )
if err != nil {
t . Fatal ( err )
}
cmd := exec . Command ( dockerBinary , "build" , "--rm=false" , "--memory=64m" , "--memory-swap=-1" , "--cpuset-cpus=1" , "--cpu-shares=100" , "-t" , name , "." )
cmd . Dir = ctx . Dir
out , _ , err := runCommandWithOutput ( cmd )
if err != nil {
t . Fatal ( err , out )
}
out , _ , err = dockerCmd ( t , "ps" , "-lq" )
if err != nil {
t . Fatal ( err , out )
}
cID := stripTrailingCharacters ( out )
type hostConfig struct {
Memory float64 // Use float64 here since the json decoder sees it that way
MemorySwap int
CpusetCpus string
CpuShares int
}
cfg , err := inspectFieldJSON ( cID , "HostConfig" )
if err != nil {
t . Fatal ( err )
}
var c1 hostConfig
if err := json . Unmarshal ( [ ] byte ( cfg ) , & c1 ) ; err != nil {
t . Fatal ( err , cfg )
}
mem := int64 ( c1 . Memory )
if mem != 67108864 || c1 . MemorySwap != - 1 || c1 . CpusetCpus != "1" || c1 . CpuShares != 100 {
t . Fatalf ( "resource constraints not set properly:\nMemory: %d, MemSwap: %d, CpusetCpus: %s, CpuShares: %d" ,
mem , c1 . MemorySwap , c1 . CpusetCpus , c1 . CpuShares )
}
// Make sure constraints aren't saved to image
_ , _ , err = dockerCmd ( t , "run" , "--name=test" , name )
if err != nil {
t . Fatal ( err )
}
cfg , err = inspectFieldJSON ( "test" , "HostConfig" )
if err != nil {
t . Fatal ( err )
}
var c2 hostConfig
if err := json . Unmarshal ( [ ] byte ( cfg ) , & c2 ) ; err != nil {
t . Fatal ( err , cfg )
}
mem = int64 ( c2 . Memory )
if mem == 67108864 || c2 . MemorySwap == - 1 || c2 . CpusetCpus == "1" || c2 . CpuShares == 100 {
t . Fatalf ( "resource constraints leaked from build:\nMemory: %d, MemSwap: %d, CpusetCpus: %s, CpuShares: %d" ,
mem , c2 . MemorySwap , c2 . CpusetCpus , c2 . CpuShares )
}
logDone ( "build - resource constraints applied" )
}